Advertisement
Guest User

benchmark

a guest
Dec 12th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.41 KB | None | 0 0
  1. #include <stdlib.h> /*malloc, free*/
  2. #include <stdio.h> /*printf*/
  3. #include <ucontext.h> /*context functionality*/
  4. #include <assert.h> /*assert*/
  5. #include <signal.h>
  6. #include <sys/time.h>
  7. #include "green.h"
  8. #include <pthread.h>
  9. #include <time.h>
  10.  
  11. #define PERIOD 100
  12. #define FALSE 0
  13. #define TRUE 1
  14. #define STACK_SIZE 4096
  15. #define MAX 1000000
  16.  
  17. static ucontext_t main_cntx = {0};
  18. static green_t main_green = {&main_cntx, NULL, NULL, NULL, NULL, FALSE};
  19. static green_t* running = &main_green;
  20. static sigset_t block;
  21.  
  22. pthread_cond_t emptyP, fullP;
  23. pthread_mutex_t mutexP;
  24.  
  25. static void init () __attribute__ ((constructor));
  26. void timer_handler(int sig);
  27.  
  28. void init () {
  29. getcontext (&main_cntx);
  30. sigemptyset(&block);
  31. sigaddset(&block, SIGVTALRM);
  32.  
  33. struct sigaction act = {0};
  34. struct timeval interval;
  35. struct itimerval period;
  36.  
  37. act.sa_handler = timer_handler;
  38. assert(sigaction(SIGVTALRM, &act, NULL) == 0);
  39.  
  40. interval.tv_sec = 0;
  41. interval.tv_usec = PERIOD;
  42. period.it_interval = interval;
  43. period.it_value = interval;
  44. setitimer(ITIMER_VIRTUAL, &period, NULL);
  45. }
  46.  
  47. struct Queue {
  48. green_t* front;
  49. green_t* end;
  50. };
  51. struct Queue* queue;
  52.  
  53. // Function to add a key to queue
  54. void myEnQueue(green_t* new) {
  55.  
  56. if (queue->end == NULL) {
  57. queue->front = queue->end = new;
  58. return;
  59. }
  60. queue->end->next = new;
  61. queue->end = new;
  62. }
  63.  
  64. // Function to remove a key from queue
  65. struct green_t* myDeQueue() {
  66. if (queue->front == NULL) {
  67. return NULL;
  68. }
  69. //printf("1: queue->front = %p \n", queue->front);
  70. struct green_t* temp = queue->front;
  71. //temp->next = NULL;
  72. queue->front = queue->front->next;
  73. temp->next = NULL;
  74. if (queue->front == NULL) {
  75. queue->end = NULL;
  76. } else {
  77. //printf("2: queue->front = %p \n", queue->front);
  78. }
  79. return temp;
  80. }
  81.  
  82. void removeFromReadyList(green_t* remove) {
  83. struct green_t* temp = queue->front;
  84. struct green_t* afterTemp = temp->next;
  85. if (temp == remove) {
  86. queue->front = queue->front->next;
  87. //printf("if (temp == remove), queue->front = %p \n", queue->front);
  88. return;
  89. }
  90. while (afterTemp != remove) {
  91. temp = temp->next;
  92. afterTemp = afterTemp->next;
  93. }
  94. if (afterTemp != NULL) {
  95. temp->next = afterTemp->next;
  96. }
  97. }
  98.  
  99. int green_mutex_init(green_mutex_t *mutex) {
  100. mutex->taken = FALSE;
  101. mutex->susp = NULL;
  102. }
  103.  
  104. int green_mutex_lock(green_mutex_t *mutex) {
  105. // block timer interrupt
  106. sigprocmask(SIG_BLOCK, &block, NULL);
  107.  
  108. green_t *susp = running;
  109. while(mutex->taken) {
  110. // suspend the running thread. Should I have a susp list?
  111. // add susp to susp queue
  112. if (mutex->susp == NULL){
  113. mutex->susp = running;
  114. } else {
  115. //I want to make sure that we add it at the end of the queue.
  116. green_t* current = mutex->susp;
  117. while(current->next != NULL){
  118. if (current->next == susp) {
  119. break;
  120. }
  121. //printf(" current->next != %p, current = %p \n", current->next, current);
  122. current = current->next;
  123. }
  124. current->next = running;
  125. running->next = NULL;
  126. }
  127.  
  128. // select the next thread for execution
  129. struct green_t* next = myDeQueue();
  130.  
  131. // find the next thread
  132. running = next;
  133. swapcontext(susp->context, next->context);
  134. }
  135. // take the lock. This is enough, the caller function will wait until it gets back,
  136. // and do whatever with the locks.
  137. mutex->taken = TRUE;
  138. //mutex->susp = running;
  139.  
  140. // unblock
  141. sigprocmask(SIG_UNBLOCK, &block, NULL);
  142. return 0;
  143. }
  144. int green_mutex_unlock(green_mutex_t *mutex) {
  145. // block timer interrupt
  146. sigprocmask(SIG_BLOCK, &block, NULL);
  147. green_t *susp = running;
  148. green_t* suspended = mutex->susp;
  149. // move suspended threads to ready queue
  150. while (suspended != NULL){
  151. if (suspended == susp) {
  152. break;
  153. }
  154. //printf(" mutex->susp != %p \n", mutex->susp);
  155. myEnQueue(suspended);
  156. if (suspended == suspended->next) {
  157. break;
  158. }
  159. suspended = suspended->next;
  160. //mutex->susp = NULL;
  161. }
  162.  
  163. mutex->taken = FALSE;
  164. mutex->susp = NULL;
  165. // unblock
  166. sigprocmask(SIG_UNBLOCK, &block, NULL);
  167. return 0;
  168. }
  169.  
  170. /*
  171. Initialize a green condition variable.
  172. */
  173. void green_cond_init(green_cond_t* cond) {
  174. cond = malloc(sizeof(struct green_cond_t));
  175. }
  176.  
  177. /*
  178. Suspend the current thread
  179. on the condition.
  180. */
  181. void green_cond_wait(green_cond_t* cond, green_mutex_t* mutex) {
  182. sigprocmask(SIG_BLOCK, &block, NULL);
  183.  
  184. //Add to cond queue
  185. green_t* this = running;
  186. if (cond->end == NULL) {
  187. cond->front = cond->end = this;
  188. }
  189. else {
  190. cond->end->next = this;
  191. cond->end = this;
  192. }
  193.  
  194. green_t *susp = running;
  195. green_t* suspended = mutex->susp;
  196. //If we have a mutex. Enqueues from seups.
  197. if(mutex != NULL) {
  198. while (suspended != NULL){
  199. if (suspended == susp) {
  200. break;
  201. }
  202. //printf(" mutex->susp != %p \n", mutex->susp);
  203. myEnQueue(suspended);
  204. if (suspended == suspended->next) {
  205. break;
  206. }
  207. suspended = suspended->next;
  208. //mutex->susp = NULL;
  209. }
  210. mutex->taken = FALSE;
  211. mutex->susp = NULL;
  212. }
  213. susp = running;
  214.  
  215. //printf("this = %p \n", this);
  216. //run next
  217. struct green_t* next = myDeQueue();
  218. //printf("next = %p \n", next);
  219. running = next;
  220. swapcontext (this->context, next->context);
  221.  
  222. if(mutex != NULL){
  223. //Try to take the lock
  224. while(mutex->taken) {
  225. //Bad luck, suspended
  226. // add susp to susp queue
  227. if (mutex->susp == NULL){
  228. mutex->susp = running;
  229. } else {
  230. //I want to make sure that we add it at the end of the queue.
  231. green_t* current = mutex->susp;
  232. while(current->next != NULL){
  233. if (current->next == susp) {
  234. break;
  235. }
  236. //printf(" current->next != %p, current = %p \n", current->next, current);
  237. current = current->next;
  238. }
  239. current->next = running;
  240. running->next = NULL;
  241. }
  242.  
  243. // select the next thread for execution
  244. struct green_t* next = myDeQueue();
  245.  
  246. // find the next thread
  247. running = next;
  248. swapcontext(susp->context, next->context);
  249. }
  250. //Take the lock
  251. mutex->taken = TRUE;
  252. }
  253. sigprocmask(SIG_UNBLOCK, &block, NULL);
  254. }
  255.  
  256. /*
  257. Move the first suspended
  258. thread to the ready cond.
  259. */
  260. void green_cond_signal(green_cond_t* cond) {
  261. sigprocmask(SIG_BLOCK, &block, NULL);
  262. if (cond->front == NULL) {
  263. return;
  264. }
  265. struct green_t* temp = cond->front;
  266. cond->front = cond->front->next;
  267. if (cond->front == NULL) {
  268. cond->end = NULL;
  269. }
  270. //printf("temp = %p \n", temp);
  271. //printf("cond->front = %p \n", cond->front);
  272. myEnQueue(temp);
  273. sigprocmask(SIG_UNBLOCK, &block, NULL);
  274. //return temp;
  275. }
  276.  
  277. /*
  278. This function is responsible for calling the function provided by the user.
  279.  
  280. This function will do (execute) two things:
  281. 1. Start the execution of the real function (the function provided by the user).
  282. 2. After returning from the call, terminate the thread.
  283.  
  284. The tricky part is what to do when the called function returns.
  285. The program should check if there is a thread waiting for its termination,
  286. if so place it in the ready queue.
  287. The stack that was allocated, and the space for the context,
  288. should be returned to the memory management system;
  289. the thread is now a zombie process.
  290. There should be a thread in the ready queue
  291. so the program select the first and schedule it for execution.
  292. */
  293. void green_thread() {
  294. sigprocmask(SIG_UNBLOCK, &block, NULL);
  295. green_t* this = running;
  296.  
  297. (*this->function)(this->arg);
  298. // place waiting (joining) thread in ready queue
  299. if (this == NULL) {
  300. //printf("this == NULL \n");
  301. }
  302. sigprocmask(SIG_BLOCK, &block, NULL);
  303. struct green_t* j = this->join;
  304. if (j != NULL) {
  305. //printf("j = %p \n", j);
  306. myEnQueue(j);
  307. //swapcontext (this->context, this->join->context);
  308. }
  309. //printf ("thread %d is done \n", *(int*)this->arg);
  310. //printf("this = %p \n", this);
  311. // free alocated memory structures, i.e. free the stack.
  312. //removeFromReadyList(this);
  313. free(this->context->uc_stack.ss_sp);
  314. free(this->context);
  315. // we're a zombie
  316. this->zombie = TRUE;
  317. //printf("Zombie \n");
  318. // find the next thread to run
  319. struct green_t* next = myDeQueue();
  320. if (next != NULL) {
  321. //printf("next = %p \n", next);
  322. running = next;
  323. setcontext (next->context);
  324. }
  325. //sigprocmask(SIG_UNBLOCK, &block, NULL);
  326. //printf("after next != NULL \n");
  327. //setcontext (this->context);
  328. }
  329.  
  330. /*create a green thread*/
  331. int green_create (green_t* new, void* (*function)(void*), void* arg) {
  332. // sigprocmask(SIG_BLOCK, &block, NULL);
  333. ucontext_t* cntx = (ucontext_t *)malloc(sizeof(ucontext_t));
  334. getcontext (cntx);
  335.  
  336. void* stack = malloc (STACK_SIZE);
  337.  
  338. cntx->uc_stack.ss_sp = stack;
  339. cntx->uc_stack.ss_size = STACK_SIZE;
  340.  
  341. makecontext (cntx, green_thread, 0);
  342. new->context = cntx;
  343. new->function = function;
  344. new->arg = arg;
  345. new->next = NULL;
  346. new->join = NULL;
  347. new->zombie = FALSE;
  348. // add new to the ready queue
  349. sigprocmask(SIG_BLOCK, &block, NULL);
  350. myEnQueue(new);
  351. sigprocmask(SIG_UNBLOCK, &block, NULL);
  352. return 0;
  353. }
  354.  
  355. /*
  356. Suspends the current thread and selects a new thread for execution.
  357.  
  358. This function will simply put the running thread last in the ready queue
  359. and then select the first thread from the queue as the next thread to run.
  360.  
  361. The call to swapcontext() will do a context switch. It will save the
  362. current state in susp->context and continue execution from next->context.
  363. Note that when the suspended thread is scheduled, it will continue the execution
  364. from exactly this point.
  365. */
  366. int green_yield () {
  367. sigprocmask(SIG_BLOCK, &block, NULL);
  368. green_t* susp = running;
  369. // add susp to ready queue
  370. myEnQueue(susp);
  371. // select the next thread for execution
  372. struct green_t* next = myDeQueue();
  373.  
  374. running = next;
  375. swapcontext (susp->context, next->context);
  376. sigprocmask(SIG_UNBLOCK, &block, NULL);
  377. return 0;
  378. }
  379.  
  380. /*
  381. The current thread is suspended waiting for a specific thread to terminate.
  382.  
  383. The join operation will wait for a thread to terminate. The program therefore add
  384. the waiting thread to the join field to the argument and select another
  385. thread for execution.
  386. If the thread has already terminated we can of course continue
  387. as if nothing happened.
  388.  
  389. The program could allow several threads to wait for the same thread.
  390. */
  391. int green_join (green_t* thread) {
  392.  
  393. if (thread->zombie) {
  394. return 0;
  395. }
  396. green_t* susp = running;
  397. sigprocmask(SIG_BLOCK, &block, NULL);
  398. // add to waiting threads
  399. //sigprocmask(SIG_BLOCK, &block, NULL);
  400. if(thread->join == NULL){
  401. thread->join = susp;
  402. } else {
  403. green_t* current = thread->join;
  404. while(current->next != NULL){
  405. current = current->next;
  406. }
  407. current->next = susp;
  408. }
  409.  
  410. //printf ("susp = %p, susp->join = %p\n", susp, susp->join);
  411. // select the next thread for execution
  412. struct green_t* next = myDeQueue();
  413.  
  414. running = next;
  415. //printf ("gonna swap\n");
  416. swapcontext (susp->context, next->context);
  417. sigprocmask(SIG_UNBLOCK, &block, NULL);
  418. //printf ("back in join\n");
  419. return 0;
  420. }
  421. void timer_handler(int sig) {
  422. sigprocmask(SIG_BLOCK, &block, NULL);
  423. green_t * susp = running;
  424.  
  425. // add the running to the ready queue. Also have to
  426. myEnQueue(susp);
  427.  
  428. // find the next thread for execution
  429. green_t* next = myDeQueue();
  430.  
  431. running = next;
  432. swapcontext(susp->context, next->context);
  433. sigprocmask(SIG_UNBLOCK, &block, NULL);
  434. }
  435.  
  436. /*
  437. --------------------------------------Testing--------------------------------------
  438. */
  439.  
  440. //new
  441. int flag = 0;
  442. green_cond_t cond;
  443. green_mutex_t mutex;
  444. int number_of_threads = 10;
  445. int counter = 0;
  446. //end new
  447.  
  448. void* test(void* arg) {
  449. int id = *(int*)arg;
  450. int loop = 4;
  451.  
  452. while(loop > 0) {
  453. if(flag == id) {
  454. printf("thread %d: %d \n", id, loop);
  455. printf("Work \n");
  456. loop--;
  457. flag = (id + 1) % 2;
  458. green_cond_signal(&cond);
  459. } else {
  460. //printf("thread %d: %d ", id, loop);
  461. //printf("Wait \n");
  462. green_cond_wait(&cond, &mutex);
  463. }
  464. }
  465. //printf("while out \n");
  466. }
  467.  
  468. void* testSharedResource(void* arg) {
  469. int id = *(int*)arg;
  470. for(int i = 0; i < 1000000; i++) {
  471. green_mutex_lock(&mutex);
  472. int temp = counter;
  473.  
  474. /*
  475. int dummy = 0;
  476. if(temp > 1337) // waste time between read and write
  477. dummy++;
  478. */
  479. printf(" count: %d, thread: %d, ", counter, id);
  480. temp++;
  481. counter = temp;
  482. green_mutex_unlock(&mutex);
  483. }
  484. }
  485.  
  486. void *test_timer(void *arg){
  487. int i = *(int*)arg;
  488. int loop = MAX;
  489. while(loop>0){
  490. loop--;
  491. counter++;
  492. printf(" count: %d, thread: %d\n",counter, i);
  493. }
  494. }
  495. /*
  496. void test_atomic(green_cond_t* cond, green_mutex_t* mutex){
  497. // green_mutex_lock(&mutex);
  498. while(1){
  499. if(flag == 0){
  500. flag = 1;
  501. green_cond_signal(&cond);
  502. break;
  503. }else {
  504. green_cond_wait(&cond, &mutex);
  505. flag = 0;
  506. }
  507. }
  508. }*/
  509. int buffer;
  510. int productions;
  511. green_cond_t full, empty;
  512. void produce() {
  513. for(int i = 0; i < productions/(number_of_threads/2); i++) {
  514. green_mutex_lock(&mutex);
  515. while(buffer == 1) {
  516. green_cond_wait(&empty, &mutex);
  517. }
  518. buffer = 1;
  519.  
  520. green_cond_signal(&full);
  521. green_mutex_unlock(&mutex);
  522. }
  523. }
  524. void consume() {
  525. for(int i = 0; i < productions/(number_of_threads/2); i++) {
  526. green_mutex_lock(&mutex);
  527. while(buffer == 0){
  528. green_cond_wait(&full, &mutex);
  529. }
  530. buffer = 0;
  531. green_cond_signal(&empty);
  532. green_mutex_unlock(&mutex);
  533. }
  534. }
  535.  
  536. void* test_consumer_producer_green(void* arg) {
  537. int id = *(int*)arg;
  538. if(id % 2 == 0) {
  539. produce();
  540. } else {
  541. consume();
  542. }
  543. }
  544. void test_green(int* args) {
  545. green_t threads[number_of_threads];
  546. for(int i = 0; i < number_of_threads; i++)
  547. green_create(&threads[i], test_consumer_producer_green, &args[i]);
  548. for(int i = 0; i < number_of_threads; i++)
  549. green_join(&threads[i]);
  550. }
  551. /***************PTHREADS*************/
  552. void produce_pthreads() {
  553. for(int i = 0; i < productions/(number_of_threads/2); i++) {
  554. pthread_mutex_lock(&mutexP);
  555. while(buffer == 1){
  556. pthread_cond_wait(&emptyP, &mutexP);
  557. }
  558. buffer = 1;
  559. pthread_cond_signal(&fullP);
  560. pthread_mutex_unlock(&mutexP);
  561. }
  562. }
  563.  
  564. void consume_pthreads() {
  565. for(int i = 0; i < productions/(number_of_threads/2); i++) {
  566. pthread_mutex_lock(&mutexP);
  567. while(buffer == 0) {
  568. pthread_cond_wait(&fullP, &mutexP);
  569. }
  570. buffer = 0;
  571. //printf("Consumed!\n");
  572. pthread_cond_signal(&emptyP);
  573. pthread_mutex_unlock(&mutexP);
  574. }
  575. }
  576. void* test_consumer_producer_pthreads(void* arg) {
  577. int id = *(int*)arg;
  578. if(id % 2 == 0) {
  579. produce_pthreads();
  580. } else {
  581. consume_pthreads();
  582. }
  583. }
  584. void test_pthreads(int* args) {
  585. pthread_t threads[number_of_threads];
  586.  
  587. for(int i = 0; i < number_of_threads; i++){
  588. pthread_create(&threads[i], NULL, test_consumer_producer_pthreads, &args[i]);
  589. }
  590. for(int i = 0; i < number_of_threads; i++){
  591. pthread_join(threads[i], NULL);
  592. }
  593. }
  594.  
  595. int main () {
  596. clock_t clock_start, c_stop;
  597. double clock_ticks_gren = 0, clock_ticks_pthreads = 0;
  598. queue = malloc(sizeof *queue);
  599.  
  600. green_cond_init(&cond);
  601. green_cond_init(&full);
  602. green_cond_init(&empty);
  603. green_mutex_init(&mutex);
  604.  
  605. pthread_cond_init(&fullP, NULL);
  606. pthread_cond_init(&emptyP, NULL);
  607. pthread_mutex_init(&mutexP, NULL);
  608.  
  609. int loops = 10;
  610. for(int run = 1; (run <= loops) && (counter<4000); run++) {
  611. buffer = 0;
  612. productions = 100 * 2 * run;
  613. int args[number_of_threads];
  614. for(int i = 0; i < number_of_threads; i++)
  615. args[i] = i;
  616.  
  617.  
  618.  
  619. clock_start = clock();
  620. test_green(args);
  621. c_stop = clock();
  622. clock_ticks_gren = ((double)(c_stop - clock_start)) / ((double)CLOCKS_PER_SEC/1000);
  623. //printf("buffer: %d\n", buffer);
  624. clock_start = clock();
  625. test_pthreads(args);
  626. c_stop = clock();
  627. clock_ticks_pthreads = ((double)(c_stop - clock_start)) / ((double)CLOCKS_PER_SEC/1000);
  628. printf("%d\t%f\t%f\n", productions, clock_ticks_gren, clock_ticks_pthreads);
  629. }
  630.  
  631. printf ("done\n");
  632. return 0;
  633. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement