zoukankan      html  css  js  c++  java
  • (转)C协程实现的效率对比

    前段时间实现的C协程依赖栈传递参数,在开启优化时会导致错误,于是实现了一个ucontext的版本,但ucontext的切换效率太差了,

    在我的机器上执行4000W次切换需要11秒左右,这达不到我的要求,所以重新设计了实现,使得在开启优化时也能得到正确的结果.

    并且效率也令人满意,4000W次切换仅需要730ms左右,足足比ucontext的实现快乐近15倍。

    下面贴出实现:

      1 #include "uthread.h"
      2 #include <stdlib.h>
      3 #include <ucontext.h>
      4 #include <pthread.h>
      5 #include "link_list.h"
      6 
      7 struct uthread
      8 {
      9     int32_t reg[8];//0:esp,1:ebp,2:eax,3:ebx,4:ecx,5:edx,6:edi,7:esi
     10     void *para;
     11     uthread_t parent;
     12     void*(*main_fun)(void*);
     13     void *stack;
     14     int32_t ssize;
     15     int8_t first_run;
     16 };
     17 
     18 #ifdef _DEBUG
     19 //for debug version
     20 void uthread_main_function()
     21 {
     22     int32_t arg;
     23      __asm__ volatile(
     24         "movl %%eax,%0	
    "
     25         :
     26         :"m"(arg)
     27     );    
     28     
     29     uthread_t u = (uthread_t)arg;
     30     void *ret = u->main_fun(u->para);
     31     if(u->parent)
     32         uthread_switch(u,u->parent,ret);
     33     else
     34         exit(0); 
     35 }
     36 #else
     37 //for release version
     38 void __attribute__((regparm(1))) uthread_main_function(void *arg)
     39 {
     40     uthread_t u = (uthread_t)arg;
     41     void *ret = u->main_fun(u->para);
     42     if(u->parent)
     43         uthread_switch(u,u->parent,ret);
     44     else
     45         exit(0);
     46 }
     47 #endif
     48 uthread_t uthread_create(uthread_t parent,void*stack,uint32_t stack_size,void*(*fun)(void*))
     49 {
     50     uthread_t u = (uthread_t)calloc(1,sizeof(*u));
     51     u->parent = parent;
     52     u->main_fun = fun;
     53     u->stack = stack;
     54     u->ssize = stack_size;
     55     if(stack)
     56     {
     57         u->reg[0] = (int32_t)stack+stack_size-4;
     58         u->reg[1] = (int32_t)stack+stack_size-4;
     59     }
     60     if(u->main_fun)
     61         u->first_run = 1;
     62     return u;
     63 }
     64 
     65 void uthread_destroy(uthread_t *u)
     66 {
     67     free(*u);
     68     *u = NULL;
     69 }
     70 
     71 #ifdef _DEBUG
     72 void* __attribute__((regparm(3))) uthread_switch(uthread_t from,uthread_t to,void *para)
     73 {
     74     if(!from)
     75         return NULL;
     76     to->para = para;
     77     int32_t esp,ebp,eax,ebx,ecx,edx,edi,esi;
     78     //save current registers
     79     //the order is important    
     80      __asm__ volatile(
     81         "movl %%eax,%2	
    "
     82         "movl %%ebx,%3	
    "
     83         "movl %%ecx,%4	
    "
     84         "movl %%edx,%5	
    "
     85         "movl %%edi,%6	
    "
     86         "movl %%esi,%7	
    "     
     87         "movl %%ebp,%1	
    "
     88         "movl %%esp,%0	
    "
     89         :
     90         :"m"(esp),"m"(ebp),"m"(eax),"m"(ebx),"m"(ecx),"m"(edx),"m"(edi),"m"(esi)
     91     );
     92     from->reg[0] = esp;
     93     from->reg[1] = ebp;
     94     from->reg[2] = eax;
     95     from->reg[3] = ebx;
     96     from->reg[4] = ecx;
     97     from->reg[5] = edx;
     98     from->reg[6] = edi;
     99     from->reg[7] = esi;    
    100     if(to->first_run)
    101     {
    102        to->first_run = 0;
    103        esp = to->reg[0];
    104        //use eax to pass arg
    105        eax = (int32_t)to;
    106         __asm__ volatile (
    107             "movl %1,%%eax	
    "
    108             "movl %0,%%ebp	
    "
    109             "movl %%ebp,%%esp	
    "
    110             :
    111             :"m"(esp),"m"(eax)
    112         );       
    113        uthread_main_function();
    114     }
    115     else
    116     {
    117         esp = to->reg[0];
    118         ebp = to->reg[1];
    119         eax = to->reg[2];
    120         ebx = to->reg[3];
    121         ecx = to->reg[4];
    122         edx = to->reg[5];
    123         edi = to->reg[6];
    124         esi = to->reg[7];
    125         //the order is important
    126         __asm__ volatile (
    127             "movl %2,%%eax	
    "
    128             "movl %3,%%ebx	
    "
    129             "movl %4,%%ecx	
    "
    130             "movl %5,%%edx	
    "
    131             "movl %6,%%edi	
    "
    132             "movl %7,%%esi	
    "        
    133             "movl %1,%%ebp	
    "
    134             "movl %0,%%esp	
    "
    135             :
    136             :"m"(esp),"m"(ebp),"m"(eax),"m"(ebx),"m"(ecx),"m"(edx),"m"(edi),"m"(esi)
    137         );
    138     }    
    139     return from->para;
    140 }
    141 #else
    142 void* __attribute__((regparm(3))) uthread_switch(uthread_t from,uthread_t to,void *para)
    143 {
    144     if(!from)
    145         return NULL;
    146     to->para = para;
    147     int32_t esp,ebp,edi,esi;
    148     //save current registers
    149     //the order is important    
    150      __asm__ volatile(
    151         "movl %%eax,%2	
    "
    152         "movl %%ebx,%3	
    "
    153         "movl %%ecx,%4	
    "
    154         "movl %%edx,%5	
    "
    155         "movl %%edi,%6	
    "
    156         "movl %%esi,%7	
    "     
    157         "movl %%ebp,%1	
    "
    158         "movl %%esp,%0	
    "
    159         :
    160         :"m"(from->reg[0]),"m"(from->reg[1]),"m"(from->reg[2]),"m"(from->reg[3])
    161         ,"m"(from->reg[4]),"m"(from->reg[5]),"m"(from->reg[6]),"m"(from->reg[7])
    162     );
    163     if(to->first_run)
    164     {
    165        to->first_run = 0;   
    166        //change stack
    167        //the order is important
    168         __asm__ volatile (
    169             "movl %0,%%ebp	
    "
    170             "movl %%ebp,%%esp	
    "
    171             :
    172             :"m"(to->reg[0])
    173         );               
    174        uthread_main_function((void*)to);
    175     }
    176     else
    177     {
    178         esp = to->reg[0];
    179         ebp = to->reg[1];
    180         edi = to->reg[6];
    181         esi = to->reg[7];
    182         //the order is important
    183         __asm__ volatile (
    184             "movl %2,%%eax	
    "
    185             "movl %3,%%ebx	
    "
    186             "movl %4,%%ecx	
    "
    187             "movl %5,%%edx	
    "
    188             "movl %6,%%edi	
    "
    189             "movl %7,%%esi	
    "        
    190             "movl %1,%%ebp	
    "
    191             "movl %0,%%esp	
    "
    192             :
    193             :"m"(esp),"m"(ebp),"m"(to->reg[2]),"m"(to->reg[3])
    194             ,"m"(to->reg[4]),"m"(to->reg[5]),"m"(edi),"m"(esi)
    195         );
    196     }    
    197     return from->para;
    198 }
    199 #endif

    test.c

     1 #include <stdio.h>
     2 #include "uthread.h"
     3 #include "SysTime.h"
     4 #include <stdlib.h>
     5 void* ufun2(void *arg)
     6 {
     7     printf("ufun2
    ");
     8     char **tmp = (char**)arg;
     9     uthread_t self = (uthread_t)tmp[0];
    10     uthread_t parent = (uthread_t)tmp[1];
    11     volatile void *ptr = self;
    12     while(ptr)
    13     {
    14         ptr = uthread_switch(self,parent,NULL);
    15     }
    16     return NULL;
    17 }
    18 
    19 char *stack1;
    20 char *stack2;
    21 
    22 void* ufun1(void *arg)
    23 {
    24     uthread_t self = (uthread_t)arg;
    25     uthread_t u = uthread_create(self,stack2,4096,ufun2);
    26     char* _arg[2];
    27     _arg[0] = (char*)u;
    28     _arg[1] = (char*)self;
    29     int i = 0;
    30     uint32_t tick = GetSystemMs();
    31     for( ; i < 20000000; ++i)
    32     {
    33         uthread_switch(self,u,&_arg[0]);
    34     }
    35     printf("%d
    ",GetSystemMs()-tick);
    36     uthread_switch(self,u,NULL);
    37     return arg;
    38 }
    39 
    40 int main()
    41 {
    42     stack1 = (char*)malloc(4096);
    43     stack2 = (char*)malloc(4096);
    44     /*
    45      * if use ucontext version
    46     char dummy_stack[4096];
    47     uthread_t p = uthread_create(NULL,dummy_stack,0,NULL);
    48     */
    49     uthread_t p = uthread_create(NULL,NULL,0,NULL);
    50     uthread_t u = uthread_create(p,stack1,4096,ufun1);
    51     uthread_switch(p,u,u);
    52     printf("main end
    ");
    53     return 0;
    54 };

    转自:https://www.cnblogs.com/sniperHW/archive/2012/08/05/2624334.html

  • 相关阅读:
    python爬虫--requests模块
    相关基础概念
    python--用python操作Git
    celery异步,延时任务, 周期任务
    Ansible剧本中的角色—playbook中的roles
    Ansible中的剧本 ansible--playbook
    ansible模块总结2-- file, fetch, yum, pip, service, cron, user, group
    Ansible--安装,命令格式, ssh, command, shell, script, copy
    python--openpyxl模块使用, 对excel表格的操作
    Git使用02--branch分支, tag版本, 忽略文件 .gitingore
  • 原文地址:https://www.cnblogs.com/heluan/p/9899994.html
Copyright © 2011-2022 走看看