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

  • 相关阅读:
    jquery 序列化form表单
    nginx for windows 安装
    nodejs idea 创建项目 (一)
    spring 配置 shiro rememberMe
    idea 2018 解决 双击shift 弹出 search everywhere 搜索框的方法
    redis 在windows 集群
    spring IOC控制反转和DI依赖注入
    redis 的安装
    shiro 通过jdbc连接数据库
    handlebars的用法
  • 原文地址:https://www.cnblogs.com/heluan/p/9899994.html
Copyright © 2011-2022 走看看