3030#define __USE_GNU
3131#include <dlfcn.h>
3232
33+ #define _GNU_SOURCE
34+ #include <sched.h>
35+
3336/* Mount points are named after filesystem types so they should never
3437 * be longer than ~6 characters. */
3538#define MAX_FSTYPE_LEN 50
@@ -177,6 +180,28 @@ void fixup_netdev_linux_fdnet_ops(void)
177180 lkl_netdev_linux_fdnet_ops .eventfd = dlsym (RTLD_NEXT , "eventfd" );
178181}
179182
183+ static void PinToCpus (const cpu_set_t * cpus )
184+ {
185+ if (sched_setaffinity (0 , sizeof (cpu_set_t ), cpus )) {
186+ perror ("sched_setaffinity" );
187+ }
188+ }
189+
190+ static void PinToFirstCpu (const cpu_set_t * cpus )
191+ {
192+ int j ;
193+ cpu_set_t pinto ;
194+ CPU_ZERO (& pinto );
195+ for (j = 0 ; j < CPU_SETSIZE ; j ++ ) {
196+ if (CPU_ISSET (j , cpus )) {
197+ lkl_printf ("LKL: Pin To CPU %d\n" , j );
198+ CPU_SET (j , & pinto );
199+ PinToCpus (& pinto );
200+ return ;
201+ }
202+ }
203+ }
204+
180205void __attribute__((constructor (102 )))
181206hijack_init (void )
182207{
@@ -195,6 +220,51 @@ hijack_init(void)
195220 char * mount = getenv ("LKL_HIJACK_MOUNT" );
196221 struct lkl_netdev * nd = NULL ;
197222 char * arp_entries = getenv ("LKL_HIJACK_NET_ARP" );
223+ /* single_cpu mode:
224+ * 0: Don't pin to single CPU (default).
225+ * 1: Pin only LKL kernel threads to single CPU.
226+ * 2: Pin all LKL threads to single CPU including all LKL kernel threads
227+ * and device polling threads. Avoid this mode if having busy polling
228+ * threads.
229+ *
230+ * mode 2 can achieve better TCP_RR but worse TCP_STREAM than mode 1.
231+ * You should choose the best for your application and virtio device
232+ * type.
233+ */
234+ char * single_cpu = getenv ("LKL_HIJACK_SINGLE_CPU" );
235+ int single_cpu_mode = 0 ;
236+ cpu_set_t ori_cpu ;
237+
238+ if (!debug )
239+ lkl_host_ops .print = NULL ;
240+ else
241+ lkl_register_dbg_handler ();
242+
243+ if (single_cpu ) {
244+ single_cpu_mode = atoi (single_cpu );
245+ switch (single_cpu_mode ) {
246+ case 0 :
247+ case 1 :
248+ case 2 : break ;
249+ default :
250+ fprintf (stderr , "single cpu mode must be 0~2.\n" );
251+ single_cpu_mode = 0 ;
252+ break ;
253+ }
254+ }
255+
256+ if (single_cpu_mode ) {
257+ if (sched_getaffinity (0 , sizeof (cpu_set_t ), & ori_cpu )) {
258+ perror ("sched_getaffinity" );
259+ single_cpu_mode = 0 ;
260+ }
261+ }
262+
263+ /* Pin to a single cpu.
264+ * Any children thread created after it are pinned to the same CPU.
265+ */
266+ if (single_cpu_mode == 2 )
267+ PinToFirstCpu (& ori_cpu );
198268
199269 /* Must be run before lkl_netdev_tap_create */
200270 fixup_netdev_linux_fdnet_ops ();
@@ -238,17 +308,19 @@ hijack_init(void)
238308 nd_id = ret ;
239309 }
240310
241- if (!debug )
242- lkl_host_ops .print = NULL ;
243- else
244- lkl_register_dbg_handler ();
311+ if (single_cpu_mode == 1 )
312+ PinToFirstCpu (& ori_cpu );
245313
246314 ret = lkl_start_kernel (& lkl_host_ops , 64 * 1024 * 1024 , "" );
247315 if (ret ) {
248316 fprintf (stderr , "can't start kernel: %s\n" , lkl_strerror (ret ));
249317 return ;
250318 }
251319
320+ /* restore cpu affinity */
321+ if (single_cpu_mode )
322+ PinToCpus (& ori_cpu );
323+
252324 /* fillup FDs up to LKL_FD_OFFSET */
253325 ret = lkl_sys_mknod ("/dev_null" , LKL_S_IFCHR | 0600 , LKL_MKDEV (1 , 3 ));
254326 dev_null = lkl_sys_open ("/dev_null" , LKL_O_RDONLY , 0 );
0 commit comments