virtualization_direct_execution.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * 1. Measure the cost of system call
  3. * about 0.6 clock tick (us)
  4. * 2. Measure the context switch
  5. * about 25 clock tick (us)
  6. * but when affinity is set to same CPU
  7. * it is reduced to 7/6/10 (us)
  8. */
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/wait.h>
  12. #include <sys/time.h>
  13. #include <fcntl.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <stdint.h>
  19. #include <inttypes.h>
  20. #include <time.h>
  21. #define _GNU_SOURCE
  22. #define __USE_GNU
  23. #include <sched.h>
  24. static const char* dir_path = "dummy";
  25. #define COUNTER 1000
  26. /*
  27. Abstraction
  28. */
  29. typedef uint64_t (*get_time_func)(void);
  30. typedef void (*print_time_func)(uint64_t);
  31. struct time_counter
  32. {
  33. /* private */
  34. get_time_func __get_time;
  35. print_time_func __print_time;
  36. uint64_t __time;
  37. };
  38. static void
  39. time_counter_start(struct time_counter* counter)
  40. {
  41. counter->__time = counter->__get_time();
  42. }
  43. static void
  44. time_counter_stop(struct time_counter* counter)
  45. {
  46. uint64_t time = counter->__get_time();
  47. counter->__time = time - counter->__time;
  48. }
  49. static void
  50. time_counter_print(const struct time_counter* counter)
  51. {
  52. counter->__print_time(counter->__time);
  53. }
  54. /*
  55. * gettimeofday implementation
  56. */
  57. static uint64_t
  58. gettimeofday_get_time(void)
  59. {
  60. struct timeval tv;
  61. if (gettimeofday(&tv, NULL) == -1)
  62. {
  63. exit(EXIT_FAILURE);
  64. }
  65. /* ignore seconds */
  66. return tv.tv_usec;
  67. }
  68. static void
  69. gettimeofday_print_time(uint64_t time)
  70. {
  71. printf("gettimeofday: %" PRIu64 " us\n", time);
  72. }
  73. /*
  74. * read time stamp counter implementation
  75. */
  76. static uint64_t
  77. rdtsc_get_time(void)
  78. {
  79. uint32_t hi, lo;
  80. asm("rdtsc"
  81. : "=a" (lo), "=d" (hi));
  82. return (uint64_t)hi << 32 | lo;
  83. }
  84. static void
  85. tick_print_time(uint64_t time)
  86. {
  87. int usec_res = CLOCKS_PER_SEC / 1000000;
  88. printf("ticks: %" PRIu64 " ticks | resolution: %d clock tick per us\n",
  89. time,
  90. usec_res);
  91. }
  92. /*
  93. * clock glibc implementation
  94. */
  95. static uint64_t
  96. clock_get_time(void)
  97. {
  98. return clock();
  99. }
  100. /* system call function */
  101. volatile static void
  102. call_system_call(size_t syscall_num)
  103. {
  104. int fd;
  105. if ((fd = open(dir_path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) == -1)
  106. {
  107. perror("cannot open file");
  108. exit(EXIT_FAILURE);
  109. }
  110. size_t counter = syscall_num;
  111. char *buff;
  112. while (counter--)
  113. {
  114. read(fd, buff, 0);
  115. }
  116. close(fd);
  117. }
  118. /* factory method */
  119. enum measurement_method
  120. {
  121. gettimeofday_method,
  122. rdtsc_method,
  123. clock_method,
  124. };
  125. static struct time_counter
  126. obtain_counter(enum measurement_method method)
  127. {
  128. struct time_counter counter;
  129. switch(method)
  130. {
  131. case gettimeofday_method:
  132. counter.__get_time = gettimeofday_get_time;
  133. counter.__print_time = gettimeofday_print_time;
  134. break;
  135. case rdtsc_method:
  136. counter.__get_time = rdtsc_get_time;
  137. counter.__print_time = tick_print_time;
  138. break;
  139. case clock_method:
  140. counter.__get_time = clock_get_time;
  141. counter.__print_time = tick_print_time;
  142. break;
  143. default:
  144. fprintf(stderr, "measurement method not supported!\n");
  145. exit(EXIT_FAILURE);
  146. }
  147. counter.__time = 0;
  148. return counter;
  149. }
  150. static void
  151. print_cpu_affinity(void)
  152. {
  153. printf("CPU: %d\n", sched_getcpu());
  154. }
  155. static void
  156. place_on_single_cpu(int cpu, pid_t pid)
  157. {
  158. cpu_set_t cpuset;
  159. CPU_ZERO(&cpuset);
  160. CPU_SET(cpu, &cpuset);
  161. sched_setaffinity(pid, CPU_SETSIZE, &cpuset);
  162. }
  163. int
  164. main(void)
  165. {
  166. place_on_single_cpu(sched_getcpu(), getpid());
  167. struct time_counter counter = obtain_counter(clock_method);
  168. /* measure system call */
  169. time_counter_start(&counter);
  170. call_system_call(COUNTER);
  171. time_counter_stop(&counter);
  172. printf("measure %dx system call\n", COUNTER);
  173. time_counter_print(&counter);
  174. puts("");
  175. /* measure context switch */
  176. int pipefd[2];
  177. if (pipe(pipefd) == -1) {
  178. perror("pipe");
  179. exit(EXIT_FAILURE);
  180. }
  181. int rc;
  182. const char *dummy_text = "switched context";
  183. if ((rc = fork()) == 0) {
  184. print_cpu_affinity();
  185. close(pipefd[0]);
  186. write(pipefd[1], dummy_text, strlen(dummy_text));
  187. exit(EXIT_SUCCESS);
  188. }
  189. print_cpu_affinity();
  190. close(pipefd[1]);
  191. char buffer[100];
  192. ssize_t bytes;
  193. puts("measure context switch");
  194. time_counter_start(&counter);
  195. while ((bytes = read(pipefd[0], buffer, 100)) > 0)
  196. {
  197. time_counter_stop(&counter);
  198. buffer[bytes] = '\0';
  199. printf("msg receivd: %s\n", buffer);
  200. }
  201. time_counter_print(&counter);
  202. wait(NULL);
  203. return EXIT_SUCCESS;
  204. }