netcpu_looper.c
Upload User: kvgkvg
Upload Date: 2015-05-07
Package Size: 1129k
Code Size: 19k
Development Platform:

C/C++

  1. char   netcpu_looper_id[]="
  2. @(#)netcpu_looper.c (c) Copyright 2005-2007. Version 2.4.3";
  3. /* netcpu_looper.c
  4.   
  5.    Implement the soaker process specific portions of netperf CPU
  6.    utilization measurements. These are broken-out into a separate file
  7.    to make life much nicer over in netlib.c which had become a maze of
  8.    twisty, CPU-util-related, #ifdefs, all different.  raj 2005-01-26
  9.    */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdio.h>
  14. #ifdef HAVE_FCNTL_H
  15. # include <fcntl.h>
  16. #endif
  17. #if HAVE_UNISTD_H
  18. # include <unistd.h>
  19. #endif
  20. #if defined(HAVE_MMAP) || defined(HAVE_SYS_MMAN_H)
  21. # include <sys/mman.h>
  22. #else
  23. # error netcpu_looper requires mmap
  24. #endif
  25. #if TIME_WITH_SYS_TIME
  26. # include <sys/time.h>
  27. # include <time.h>
  28. #else
  29. # if HAVE_SYS_TIME_H
  30. #  include <sys/time.h>
  31. # else
  32. #  include <time.h>
  33. # endif
  34. #endif
  35. #if HAVE_SYS_TYPES_H
  36. # include <sys/types.h>
  37. #endif
  38. #if HAVE_SYS_WAIT_H
  39. # include <sys/wait.h>
  40. #endif
  41. #ifdef HAVE_SIGNAL_H
  42. #include <signal.h>
  43. #endif
  44. #ifdef HAVE_ERRNO_H
  45. #include <errno.h>
  46. #endif
  47. #include "netsh.h"
  48. #include "netlib.h"
  49. #define PAGES_PER_CHILD 2
  50. /* the lib_start_count and lib_end_count arrays hold the starting
  51.    and ending values of whatever is counting when the system is
  52.    idle. The rate at which this increments during a test is compared
  53.    with a previous calibrarion to arrive at a CPU utilization
  54.    percentage. raj 2005-01-26 */
  55. static uint64_t  lib_start_count[MAXCPUS];
  56. static uint64_t  lib_end_count[MAXCPUS];
  57. static int *cpu_mappings;
  58. static int lib_idle_fd;
  59. static uint64_t *lib_idle_address[MAXCPUS];
  60. static long     *lib_base_pointer;
  61. static pid_t     lib_idle_pids[MAXCPUS];
  62. static int       lib_loopers_running=0;
  63. /* we used to use this code to bind the loopers, but since we have
  64.    decided to enable processor affinity for the actual
  65.    netperf/netserver processes we will use that affinity routine,
  66.    which happens to know about more systems than this */
  67. #ifdef NOTDEF
  68. static void
  69. bind_to_processor(int child_num)
  70. {
  71.   /* This routine will bind the calling process to a particular */
  72.   /* processor. We are not choosy as to which processor, so it will be */
  73.   /* the process id mod the number of processors - shifted by one for */
  74.   /* those systems which name processor starting from one instead of */
  75.   /* zero. on those systems where I do not yet know how to bind a */
  76.   /* process to a processor, this routine will be a no-op raj 10/95 */
  77.   /* just as a reminder, this is *only* for the looper processes, not */
  78.   /* the actual measurement processes. those will, should, MUST float */
  79.   /* or not float from CPU to CPU as controlled by the operating */
  80.   /* system defaults. raj 12/95 */
  81. #ifdef __hpux
  82. #include <sys/syscall.h>
  83. #include <sys/mp.h>
  84.   int old_cpu = -2;
  85.   if (debug) {
  86.     fprintf(where,
  87.             "child %d asking for CPU %d as pid %d with %d CPUsn",
  88.             child_num,
  89.             (child_num % lib_num_loc_cpus),
  90.             getpid(),
  91.             lib_num_loc_cpus);
  92.     fflush(where);
  93.   }
  94.   SETPROCESS((child_num % lib_num_loc_cpus), getpid());
  95.   return;
  96. #else
  97. #if defined(__sun) && defined(__SVR4)
  98.  /* should only be Solaris */
  99. #include <sys/processor.h>
  100. #include <sys/procset.h>
  101.   int old_binding;
  102.   if (debug) {
  103.     fprintf(where,
  104.             "bind_to_processor: child %d asking for CPU %d as pid %d with %d CPUsn",
  105.             child_num,
  106.             (child_num % lib_num_loc_cpus),
  107.             getpid(),
  108.             lib_num_loc_cpus);
  109.     fflush(where);
  110.   }
  111.   if (processor_bind(P_PID,
  112.                      getpid(),
  113.                      (child_num % lib_num_loc_cpus), 
  114.                       &old_binding) != 0) {
  115.     fprintf(where,"bind_to_processor: unable to perform processor bindingn");
  116.     fprintf(where,"                   errno %dn",errno);
  117.     fflush(where);
  118.   }
  119.   return;
  120. #else
  121. #ifdef WIN32
  122.   if (!SetThreadAffinityMask(GetCurrentThread(), (ULONG_PTR)1 << (child_num % lib_num_loc_cpus))) {
  123.     perror("SetThreadAffinityMask failed");
  124.     fflush(stderr);
  125.   }
  126.   if (debug) {
  127.     fprintf(where,
  128.             "bind_to_processor: child %d asking for CPU %d of %d CPUsn",
  129.             child_num,
  130.             (child_num % lib_num_loc_cpus),
  131.             lib_num_loc_cpus);
  132.     fflush(where);
  133.   }
  134. #endif
  135.   return;
  136. #endif /* __sun && _SVR4 */
  137. #endif /* __hpux */
  138. }
  139. #endif
  140.  /* sit_and_spin will just spin about incrementing a value */
  141.  /* this value will either be in a memory mapped region on Unix shared */
  142.  /* by each looper process, or something appropriate on Windows/NT */
  143.  /* (malloc'd or such). This routine is reasonably ugly in that it has */
  144.  /* priority manipulating code for lots of different operating */
  145.  /* systems. This routine never returns. raj 1/96 */ 
  146. static void
  147. sit_and_spin(int child_index)
  148. {
  149.   uint64_t *my_counter_ptr;
  150.  /* only use C stuff if we are not WIN32 unless and until we */
  151.  /* switch from CreateThread to _beginthread. raj 1/96 */
  152. #ifndef WIN32
  153.   /* we are the child. we could decide to exec some separate */
  154.   /* program, but that doesn't really seem worthwhile - raj 4/95 */
  155.   if (debug > 1) {
  156.     fprintf(where,
  157.             "Looper child %d is born, pid %dn",
  158.             child_index,
  159.             getpid());
  160.     fflush(where);
  161.   }
  162.   
  163. #endif /* WIN32 */
  164.   /* reset our base pointer to be at the appropriate offset */
  165.   my_counter_ptr = (uint64_t *) ((char *)lib_base_pointer + 
  166.                              (netlib_get_page_size() * 
  167.                               PAGES_PER_CHILD * child_index));
  168.   
  169.   /* in the event we are running on an MP system, it would */
  170.   /* probably be good to bind the soaker processes to specific */
  171.   /* processors. I *think* this is the most reasonable thing to */
  172.   /* do, and would be closes to simulating the information we get */
  173.   /* on HP-UX with pstat. I could put all the system-specific code */
  174.   /* here, but will "abstract it into another routine to keep this */
  175.   /* area more readable. I'll probably do the same thine with the */
  176.   /* "low pri code" raj 10/95 */
  177.   
  178.   /* since we are "flying blind" wrt where we should bind the looper
  179.      processes, we want to use the cpu_map that was prepared by netlib
  180.      rather than assume that the CPU ids on the system start at zero
  181.      and are contiguous. raj 2006-04-03 */
  182.   bind_to_specific_processor(child_index % lib_num_loc_cpus,1);
  183.   
  184.   for (*my_counter_ptr = 0L;
  185.        ;
  186.        (*my_counter_ptr)++) {
  187.     if (!(*lib_base_pointer % 1)) {
  188.       /* every once and again, make sure that our process priority is */
  189.       /* nice and low. also, by making system calls, it may be easier */
  190.       /* for us to be pre-empted by something that needs to do useful */
  191.       /* work - like the thread of execution actually sending and */
  192.       /* receiving data across the network :) */
  193. #ifdef _AIX
  194.       int pid,prio;
  195.       prio = PRIORITY;
  196.       pid = getpid();
  197.       /* if you are not root, this call will return EPERM - why one */
  198.       /* cannot change one's own priority to  lower value is beyond */
  199.       /* me. raj 2/26/96 */  
  200.       setpri(pid, prio);
  201. #else /* _AIX */
  202. #ifdef __sgi
  203.       int pid,prio;
  204.       prio = PRIORITY;
  205.       pid = getpid();
  206.       schedctl(NDPRI, pid, prio);
  207.       sginap(0);
  208. #else /* __sgi */
  209. #ifdef WIN32
  210.       SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE);
  211. #else /* WIN32 */
  212. #if defined(__sun) && defined(__SVR4)
  213. #include <sys/types.h>
  214. #include <sys/priocntl.h>
  215. #include <sys/rtpriocntl.h>
  216. #include <sys/tspriocntl.h>
  217.       /* I would *really* like to know how to use priocntl to make the */
  218.       /* priority low for this looper process. however, either my mind */
  219.       /* is addled, or the manpage in section two for priocntl is not */
  220.       /* terribly helpful - for one, it has no examples :( so, if you */
  221.       /* can help, I'd love to hear from you. in the meantime, we will */
  222.       /* rely on nice(39). raj 2/26/96 */
  223.       nice(39);
  224. #else /* __sun && __SVR4 */
  225.       nice(39);
  226. #endif /* __sun && _SVR4 */
  227. #endif /* WIN32 */
  228. #endif /* __sgi */
  229. #endif /* _AIX */
  230.     }
  231.   }
  232. }
  233.  /* this routine will start all the looper processes or threads for */
  234.  /* measuring CPU utilization. */
  235. static void
  236. start_looper_processes()
  237. {
  238.   unsigned int      i, file_size;
  239.   
  240.   /* we want at least two pages for each processor. the */
  241.   /* child for any one processor will write to the first of his two */
  242.   /* pages, and the second page will be a buffer in case there is page */
  243.   /* prefetching. if your system pre-fetches more than a single page, */
  244.   /* well, you'll have to modify this or live with it :( raj 4/95 */
  245.   file_size = ((netlib_get_page_size() * PAGES_PER_CHILD) * 
  246.                lib_num_loc_cpus);
  247.   
  248. #ifndef WIN32
  249.   /* we we are not using WINDOWS NT (or 95 actually :), then we want */
  250.   /* to create a memory mapped region so we can see all the counting */
  251.   /* rates of the loopers */
  252.   /* could we just use an anonymous memory region for this? it is */
  253.   /* possible that using a mmap()'ed "real" file, while convenient for */
  254.   /* debugging, could result in some filesystem activity - like */
  255.   /* metadata updates? raj 4/96 */
  256.   lib_idle_fd = open("/tmp/netperf_cpu",O_RDWR | O_CREAT | O_EXCL);
  257.   
  258.   if (lib_idle_fd == -1) {
  259.     fprintf(where,"create_looper: file creation; errno %dn",errno);
  260.     fflush(where);
  261.     exit(1);
  262.   }
  263.   
  264.   if (chmod("/tmp/netperf_cpu",0644) == -1) {
  265.     fprintf(where,"create_looper: chmod; errno %dn",errno);
  266.     fflush(where);
  267.     exit(1);
  268.   }
  269.   
  270.   /* with the file descriptor in place, lets be sure that the file is */
  271.   /* large enough. */
  272.   
  273.   if (truncate("/tmp/netperf_cpu",file_size) == -1) {
  274.     fprintf(where,"create_looper: truncate: errno %dn",errno);
  275.     fflush(where);
  276.     exit(1);
  277.   }
  278.   
  279.   /* the file should be large enough now, so we can mmap it */
  280.   
  281.   /* if the system does not have MAP_VARIABLE, just define it to */
  282.   /* be zero. it is only used/needed on HP-UX (?) raj 4/95 */
  283. #ifndef MAP_VARIABLE
  284. #define MAP_VARIABLE 0x0000
  285. #endif /* MAP_VARIABLE */
  286. #ifndef MAP_FILE
  287. #define MAP_FILE 0x0000
  288. #endif /* MAP_FILE */
  289.   if ((lib_base_pointer = (long *)mmap(NULL,
  290.                                        file_size,
  291.                                        PROT_READ | PROT_WRITE,
  292.                                        MAP_FILE | MAP_SHARED | MAP_VARIABLE,
  293.                                        lib_idle_fd,
  294.                                        0)) == (long *)-1) {
  295.     fprintf(where,"create_looper: mmap: errno %dn",errno);
  296.     fflush(where);
  297.     exit(1);
  298.   }
  299.   
  300.   if (debug > 1) {
  301.     fprintf(where,"num CPUs %d, file_size %d, lib_base_pointer %pn",
  302.             lib_num_loc_cpus,
  303.             file_size,
  304.             lib_base_pointer);
  305.     fflush(where);
  306.   }
  307.   /* we should have a valid base pointer. lets fork */
  308.   
  309.   for (i = 0; i < (unsigned int)lib_num_loc_cpus; i++) {
  310.     switch (lib_idle_pids[i] = fork()) {
  311.     case -1:
  312.       perror("netperf: fork");
  313.       exit(1);
  314.     case 0:
  315.       /* we are the child. we could decide to exec some separate */
  316.       /* program, but that doesn't really seem worthwhile - raj 4/95 */
  317.       signal(SIGTERM, SIG_DFL);
  318.       sit_and_spin(i);
  319.       /* we should never really get here, but if we do, just exit(0) */
  320.       exit(0);
  321.       break;
  322.     default:
  323.       /* we must be the parent */
  324.       lib_idle_address[i] = (uint64_t *) ((char *)lib_base_pointer + 
  325.                                       (netlib_get_page_size() * 
  326.                                        PAGES_PER_CHILD * i));
  327.       if (debug) {
  328.         fprintf(where,"lib_idle_address[%d] is %pn",
  329.                 i,
  330.                 lib_idle_address[i]);
  331.         fflush(where);
  332.       }
  333.     }
  334.   }
  335. #else
  336.   /* we are compiled -DWIN32 */
  337.   if ((lib_base_pointer = malloc(file_size)) == NULL) {
  338.     fprintf(where,
  339.             "create_looper_process could not malloc %d bytesn",
  340.             file_size);
  341.     fflush(where);
  342.     exit(1);
  343.   }
  344.   /* now, create all the threads */
  345.   for(i = 0; i < (unsigned int)lib_num_loc_cpus; i++) {
  346.     long place_holder;
  347.     if ((lib_idle_pids[i] = CreateThread(0,
  348.                                          0,
  349.                                          (LPTHREAD_START_ROUTINE)sit_and_spin,
  350.                                          (LPVOID)(ULONG_PTR)i,
  351.                                          0,
  352.                                          &place_holder)) == NULL ) {
  353.       fprintf(where,
  354.               "create_looper_process: CreateThread failedn");
  355.       fflush(where);
  356.       /* I wonder if I need to look for other threads to kill? */
  357.       exit(1);
  358.     }
  359.     lib_idle_address[i] = (long *) ((char *)lib_base_pointer + 
  360.                                     (netlib_get_page_size() * 
  361.                                      PAGES_PER_CHILD * i));
  362.     if (debug) {
  363.       fprintf(where,"lib_idle_address[%d] is %pn",
  364.               i,
  365.               lib_idle_address[i]);
  366.       fflush(where);
  367.     }
  368.   }
  369. #endif /* WIN32 */
  370.   /* we need to have the looper processes settled-in before we do */
  371.   /* anything with them, so lets sleep for say 30 seconds. raj 4/95 */
  372.   sleep(30);
  373. }
  374. void
  375. cpu_util_init(void) 
  376. {
  377.   cpu_method = LOOPER;
  378.   /* we want to get the looper processes going */
  379.   if (!lib_loopers_running) {
  380.     start_looper_processes();
  381.     lib_loopers_running = 1;
  382.   }
  383.   return;
  384. }
  385. /* clean-up any left-over CPU util resources - looper processes,
  386.    files, whatever.  raj 2005-01-26 */
  387. void
  388. cpu_util_terminate() {
  389. #ifdef WIN32
  390.   /* it would seem that if/when the process exits, all the threads */
  391.   /* will go away too, so I don't think I need any explicit thread */
  392.   /* killing calls here. raj 1/96 */
  393. #else
  394.   int i;
  395.   /* now go through and kill-off all the child processes */
  396.   for (i = 0; i < lib_num_loc_cpus; i++){
  397.     /* SIGKILL can leave core files behind - thanks to Steinar Haug */
  398.     /* for pointing that out. */
  399.     kill(lib_idle_pids[i],SIGTERM);
  400.   }
  401.   lib_loopers_running = 0;
  402.   /* reap the children */
  403.   while(waitpid(-1, NULL, WNOHANG) > 0) { }
  404.   
  405.   /* finally, unlink the mmaped file */
  406.   munmap((caddr_t)lib_base_pointer,
  407.          ((netlib_get_page_size() * PAGES_PER_CHILD) * 
  408.           lib_num_loc_cpus));
  409.   unlink("/tmp/netperf_cpu");
  410. #endif
  411.   return;
  412. }
  413. int
  414. get_cpu_method(void)
  415. {
  416.   return LOOPER;
  417. }
  418.  /* calibrate_looper */
  419.  /* Loop a number of iterations, sleeping interval seconds each and */
  420.  /* count how high the idle counter gets each time. Return  the */
  421.  /* measured cpu rate to the calling routine. raj 4/95 */
  422. float
  423. calibrate_idle_rate (int iterations, int interval)
  424. {
  425.   uint64_t
  426.     firstcnt[MAXCPUS],
  427.     secondcnt[MAXCPUS];
  428.   float 
  429.     elapsed,
  430.     temp_rate,
  431.     rate[MAXTIMES],
  432.     local_maxrate;
  433.   long  
  434.     sec,
  435.     usec;
  436.   int   
  437.     i,
  438.     j;
  439.   
  440.   struct  timeval time1, time2 ;
  441.   struct  timezone tz;
  442.   
  443.   if (iterations > MAXTIMES) {
  444.     iterations = MAXTIMES;
  445.   }
  446.   local_maxrate = (float)-1.0;
  447.   
  448.   for(i = 0; i < iterations; i++) {
  449.     rate[i] = (float)0.0;
  450.     for (j = 0; j < lib_num_loc_cpus; j++) {
  451.       firstcnt[j] = *(lib_idle_address[j]);
  452.     }
  453.     gettimeofday (&time1, &tz);
  454.     sleep(interval);
  455.     gettimeofday (&time2, &tz);
  456.     if (time2.tv_usec < time1.tv_usec)
  457.       {
  458.         time2.tv_usec += 1000000;
  459.         time2.tv_sec -=1;
  460.       }
  461.     sec = time2.tv_sec - time1.tv_sec;
  462.     usec = time2.tv_usec - time1.tv_usec;
  463.     elapsed = (float)sec + ((float)usec/(float)1000000.0);
  464.     
  465.     if(debug) {
  466.       fprintf(where, "Calibration for counter run: %dn",i);
  467.       fprintf(where,"tsec = %ld usec = %ldn",sec,usec);
  468.       fprintf(where,"telapsed time = %gn",elapsed);
  469.     }
  470.     for (j = 0; j < lib_num_loc_cpus; j++) {
  471.       secondcnt[j] = *(lib_idle_address[j]);
  472.       if(debug) {
  473.         /* I know that there are situations where compilers know about */
  474.         /* long long, but the library fucntions do not... raj 4/95 */
  475.         fprintf(where,
  476.                 "tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lxn",
  477.                 j,
  478.                 (uint32_t)(firstcnt[j]>>32),
  479.                 (uint32_t)(firstcnt[j]&0xffffffff),
  480.                 j,
  481.                 (uint32_t)(secondcnt[j]>>32),
  482.                 (uint32_t)(secondcnt[j]&0xffffffff));
  483.       }
  484.       /* we assume that it would wrap no more than once. we also */
  485.       /* assume that the result of subtracting will "fit" raj 4/95 */
  486.       temp_rate = (secondcnt[j] >= firstcnt[j]) ?
  487.         (float)(secondcnt[j] - firstcnt[j])/elapsed : 
  488.           (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
  489.       if (temp_rate > rate[i]) rate[i] = temp_rate;
  490.       if(debug) {
  491.         fprintf(where,"trate[%d] = %gn",i,rate[i]);
  492.         fflush(where);
  493.       }
  494.       if (local_maxrate < rate[i]) local_maxrate = rate[i];
  495.     }
  496.   }
  497.   if(debug) {
  498.     fprintf(where,"tlocal maxrate = %g per sec. n",local_maxrate);
  499.     fflush(where);
  500.   }
  501.   return local_maxrate;
  502. }
  503. void
  504. get_cpu_idle (uint64_t *res)
  505. {
  506.   int i;
  507.   for (i = 0; i < lib_num_loc_cpus; i++){
  508.     res[i] = *lib_idle_address[i];
  509.   }
  510. }
  511. float
  512. calc_cpu_util_internal(float elapsed_time)
  513. {
  514.   int i;
  515.   float correction_factor;
  516.   float actual_rate;
  517.   lib_local_cpu_util = (float)0.0;
  518.   /* It is possible that the library measured a time other than */
  519.   /* the one that the user want for the cpu utilization */
  520.   /* calculations - for example, tests that were ended by */
  521.   /* watchdog timers such as the udp stream test. We let these */
  522.   /* tests tell up what the elapsed time should be. */
  523.   
  524.   if (elapsed_time != 0.0) {
  525.     correction_factor = (float) 1.0 + 
  526.       ((lib_elapsed - elapsed_time) / elapsed_time);
  527.   }
  528.   else {
  529.     correction_factor = (float) 1.0;
  530.   }
  531.   for (i = 0; i < lib_num_loc_cpus; i++) {
  532.     /* it would appear that on some systems, in loopback, nice is
  533.      *very* effective, causing the looper process to stop dead in its
  534.      tracks. if this happens, we need to ensure that the calculation
  535.      does not go south. raj 6/95 and if we run completely out of idle,
  536.      the same thing could in theory happen to the USE_KSTAT path. raj
  537.      8/2000 */ 
  538.     
  539.     if (lib_end_count[i] == lib_start_count[i]) {
  540.       lib_end_count[i]++;
  541.     }
  542.     
  543.     actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
  544.       (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
  545.       (float)(lib_end_count[i] - lib_start_count[i] +
  546.       MAXLONG)/ lib_elapsed;
  547.     if (debug) {
  548.       fprintf(where,
  549.               "calc_cpu_util: actual_rate on processor %d is %f start 0x%8.8lx%8.8lx end 0x%8.8lx%8.8lxn",
  550.               i,
  551.               actual_rate,
  552.               (uint32_t)(lib_start_count[i]>>32),
  553.               (uint32_t)(lib_start_count[i]&0xffffffff),
  554.               (uint32_t)(lib_end_count[i]>>32),
  555.               (uint32_t)(lib_end_count[i]&0xffffffff));
  556.     }
  557.     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
  558.       lib_local_maxrate * 100;
  559.     lib_local_cpu_util += lib_local_per_cpu_util[i];
  560.   }
  561.   /* we want the average across all n processors */
  562.   lib_local_cpu_util /= (float)lib_num_loc_cpus;
  563.   
  564.   lib_local_cpu_util *= correction_factor;
  565.   return lib_local_cpu_util;
  566. }
  567. void
  568. cpu_start_internal(void)
  569. {
  570.   get_cpu_idle(lib_start_count);
  571.   return;
  572. }
  573. void
  574. cpu_stop_internal(void)
  575. {
  576.   get_cpu_idle(lib_end_count);
  577. }