Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multithreaded tight encoding from TurboVNC #563

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,11 @@ check_include_file("netinet/in.h" LIBVNCSERVER_HAVE_NETINET_IN_H)
check_include_file("sys/endian.h" LIBVNCSERVER_HAVE_SYS_ENDIAN_H)
check_include_file("sys/socket.h" LIBVNCSERVER_HAVE_SYS_SOCKET_H)
check_include_file("sys/stat.h" LIBVNCSERVER_HAVE_SYS_STAT_H)
check_include_file("sys/sysctl.h" LIBVNCSERVER_HAVE_SYS_SYSCTL_H)
check_include_file("sys/time.h" LIBVNCSERVER_HAVE_SYS_TIME_H)
check_include_file("sys/types.h" LIBVNCSERVER_HAVE_SYS_TYPES_H)
check_include_file("sys/wait.h" LIBVNCSERVER_HAVE_SYS_WAIT_H)
check_include_file("sched.h" LIBVNCSERVER_HAVE_SCHED_H)
check_include_file("unistd.h" LIBVNCSERVER_HAVE_UNISTD_H)
check_include_file("sys/resource.h" LIBVNCSERVER_HAVE_SYS_RESOURCE_H)

Expand Down
16 changes: 16 additions & 0 deletions include/rfb/rfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ typedef UINT32 in_addr_t;
#endif
#endif

/* Maximum number of threads to use for multithreaded encoding, regardless of
the CPU count */
#define MAX_ENCODING_THREADS 8

struct _rfbClientRec;
struct _rfbScreenInfo;
struct rfbCursor;
Expand Down Expand Up @@ -372,6 +376,8 @@ typedef struct _rfbScreenInfo
#ifdef LIBVNCSERVER_HAVE_LIBZ
rfbSetXCutTextUTF8ProcPtr setXCutTextUTF8;
#endif
rfbBool rfbMT;
int rfbNumThreads;
} rfbScreenInfo, *rfbScreenInfoPtr;


Expand Down Expand Up @@ -705,6 +711,16 @@ typedef struct _rfbClientRec {
rfbBool tightUsePixelFormat24;
void *tightTJ;
int tightPngDstDataLen;

/* Multithreaded tight encoding. */

rfbBool threadInit;
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
pthread_t thnd[MAX_ENCODING_THREADS];
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
uintptr_t thnd[MAX_ENCODING_THREADS];
#endif

#endif
#endif
} rfbClientRec, *rfbClientPtr;
Expand Down
6 changes: 6 additions & 0 deletions include/rfb/rfbconfig.h.cmakein
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine LIBVNCSERVER_HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/sysctl.h> header file. */
#cmakedefine LIBVNCSERVER_HAVE_SYS_SYSCTL_H 1

/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine LIBVNCSERVER_HAVE_SYS_TIME_H 1

Expand All @@ -108,6 +111,9 @@
/* Define to 1 if you have <sys/resource.h> */
#cmakedefine LIBVNCSERVER_HAVE_SYS_RESOURCE_H 1

/* Define to 1 if you have the <sched.h> header file. */
#cmakedefine LIBVNCSERVER_HAVE_SCHED_H 1

/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine LIBVNCSERVER_HAVE_UNISTD_H 1

Expand Down
21 changes: 21 additions & 0 deletions src/libvncserver/cargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ rfbUsage(void)
fprintf(stderr, "-listenv6 ipv6addr listen for IPv6 connections only on network interface with\n");
fprintf(stderr, " addr ipv6addr. '-listen localhost' and hostname work too.\n");
#endif
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
fprintf(stderr, "-nomt disable multithreaded Tight encoding\n");
fprintf(stderr, "-nthreads N specify number of threads (1 <= N <= %d) to use with\n",
MAX_ENCODING_THREADS);
fprintf(stderr, " multithreaded Tight encoding [default: 1 per CPU core,\n");
fprintf(stderr, " max. %d]\n", MAX_ENCODING_THREADS);
#endif

for(extension=rfbGetExtensionIterator();extension;extension=extension->next)
if(extension->usage)
Expand Down Expand Up @@ -202,6 +209,20 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[])
}
rfbScreen->listen6Interface = argv[++i];
#endif
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
} else if (strcmp(argv[i], "-nomt") == 0) {
rfbScreen->rfbMT = FALSE;
} else if (strcmp(argv[i], "-nthreads") == 0) {
if (i + 1 >= *argc) {
rfbUsage();
return FALSE;
}
rfbScreen->rfbNumThreads = atoi(argv[++i]);
if (rfbScreen->rfbNumThreads < 1 || rfbScreen->rfbNumThreads > MAX_ENCODING_THREADS) {
rfbUsage();
return FALSE;
}
#endif
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
} else if (strcmp(argv[i], "-sslkeyfile") == 0) { /* -sslkeyfile sslkeyfile */
if (i + 1 >= *argc) {
Expand Down
84 changes: 84 additions & 0 deletions src/libvncserver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
* see GPL (latest version) for full details
*/

#include <rfb/rfbconfig.h>

#if LIBVNCSERVER_HAVE_SCHED_H
#define _GNU_SOURCE
#include <sched.h>
#endif

#ifdef __STRICT_ANSI__
#define _BSD_SOURCE
#endif
Expand All @@ -25,6 +32,10 @@
#define true -1
#endif

#ifdef LIBVNCSERVER_HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif

#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
Expand Down Expand Up @@ -55,6 +66,43 @@ char rfbEndianTest = (1==0);
char rfbEndianTest = (1==1);
#endif

#ifndef min
inline static int min(int a, int b)
{
return a > b ? b : a;
}
#endif

#ifdef __APPLE__
typedef struct cpu_set {
uint64_t count;
} cpu_set_t;

static inline void
CPU_ZERO(cpu_set_t *cs) { cs->count = 0; }

static inline int
CPU_COUNT(cpu_set_t *cs) { return __builtin_popcountll(cs->count); }

int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cpu_set)
{
int i;
int32_t core_count = 0;
size_t len = sizeof(core_count);
int ret = sysctlbyname("machdep.cpu.core_count", &core_count, &len, 0, 0);
if (ret) {
rfbErr("error while get core count %d\n", ret);
return -1;
}
cpu_set->count = 0;
for (i = 0; i < core_count; i++) {
cpu_set->count |= (1 << i);
}

return 0;
}
#endif

/*
* Protocol extensions
*/
Expand Down Expand Up @@ -996,11 +1044,47 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,

screen->permitFileTransfer = FALSE;

screen->rfbMT = TRUE;
screen->rfbNumThreads = 0;

if(!rfbProcessArguments(screen,argc,argv)) {
free(screen);
return NULL;
}

#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
#if defined(WIN32) || defined(__MINGW32__)
DWORD64 dwProcessAffinity, dwSystemAffinity;
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity);
#if defined(__MINGW32__)
const int np = __builtin_popcountll(dwProcessAffinity);
#else
const int np = __popcnt64(dwProcessAffinity);
#endif
#elif LIBVNCSERVER_HAVE_SCHED_H
cpu_set_t cs;
CPU_ZERO(&cs);
int cpus = -1;
if (sched_getaffinity(0, sizeof(cs), &cs) == 0) {
cpus = CPU_COUNT(&cs);
}
const int np = cpus;
#else
const int np = -1;
#endif
if (np == -1 && screen->rfbMT) {
rfbLog("WARNING: Could not determine CPU count. Multithreaded encoding disabled.\n");
screen->rfbMT = FALSE;
}
if (!screen->rfbMT) screen->rfbNumThreads = 1;
else if (screen->rfbNumThreads < 1) screen->rfbNumThreads = min(np, 4);
if (screen->rfbNumThreads > np) {
rfbLog("NOTICE: Encoding thread count has been clamped to CPU count\n");
screen->rfbNumThreads = np;
}
#endif


#ifdef WIN32
{
DWORD dummy=255;
Expand Down
9 changes: 9 additions & 0 deletions src/libvncserver/rfbserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,15 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
}
}

#ifdef LIBVNCSERVER_HAVE_LIBJPEG
/* Multithreaded tight encoding. */

cl->threadInit = FALSE;
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS)
memset(cl->thnd, 0, sizeof(cl->thnd));
#endif
#endif

for(extension = rfbGetExtensionIterator(); extension;
extension=extension->next) {
void* data = NULL;
Expand Down
Loading