周伟明的专栏

<<软件测试实践>> 已上市

用户操作
[即时聊天] [发私信] [加为好友]
周伟明ID:drzhouweiming
195148次访问,排名375好友2人,关注者27
软件技术爱好及研究者
drzhouweiming的文章
原创 50 篇
翻译 0 篇
转载 0 篇
评论 334 篇
周伟明的公告
一书已上市, 欢迎大家提出意见!
最近评论
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
文章分类
    收藏
      相册
      最近文章
      1、多核新观念-象使用内存一样使用CPU?
      2、多核编程中的任务随机竞争模式的概率分析
      3、OpenMP创建线程中的锁及原子操作性能比较
      4、多核编程中的任务分组竞争模式
      5、称球问题的测试解法
      90%程序员写不出无BUG的二分查找程序?
      C/C++代码检视实例
      多核编程中的负载平衡难题
      多核编程中的锁竞争难题
      微软过桥问题与测试人员素养
      接口关系稳定原理探索
      接口设计定理
      模块分解原理与三权分立
      模块分解原理的探索
      测试驱动需求分析
      筑一座坝治好中国的沙漠
      存档
      软件项目交易
      订阅我的博客
      XML聚合  FeedSky
      订阅到鲜果
      订阅到Google
      订阅到抓虾
      订阅到BlogLines
      订阅到Yahoo
      订阅到GouGou
      订阅到飞鸽
      订阅到Rojo
      订阅到newsgator
      订阅到netvibes

      原创 双核CPU上的快速排序效率收藏

      新一篇: OpenMP并行程序设计(一) | 旧一篇: 《多任务下的数据结构与算法》一书中的红黑树的测试代码,供读者参考!

       
      双核CPU上的快速排序效率
       
      为了试验一下多核CPU上排序算法的效率,得比较单任务情况下和多任务并行排序算法的差距,因此选用快速排序算法来进行比较。
      测试环境:双核CPU 2.66GHZ
                          单核CPU 2.4GHZ
                 
      以下是一个快速排序算法的源代码:
      UINTSplit(void **ppData, UINTuStart, UINTuEnd,
                           COMPAREFUNCCompareFunc)
      {
          void *pSelData;
          UINTuLow;
          UINTuHigh;
       
          uLow = uStart;
          uHigh = uEnd;
       
          pSelData = ppData[uLow];
          while ( uLow < uHigh )
          {
              while ( (*CompareFunc)(ppData[uHigh], pSelData) > 0
                  && uLow != uHigh )
              {
                  --uHigh;
              }
              if ( uHigh != uLow )
              {
                  ppData[uLow] = ppData[uHigh];
                  ++uLow;
              }
       
              while ( (*CompareFunc)( ppData[uLow], pSelData ) < 0
                  && uLow != uHigh )
              {
                   ++uLow;
              }
              if ( uLow != uHigh )
              {
                  ppData[uHigh] = ppData[uLow];
                  --uHigh;
              }
          }
          ppData[uLow] = pSelData;
       
          returnuLow;
      }
       
       
      voidQuickSort(void **ppData, UINTuStart, UINTuEnd,
                              COMPAREFUNCCompareFunc)
      {
          UINTuMid = Split(ppData, uStart, uEnd, CompareFunc );
          if ( uMid > uStart )
          {
              QuickSort(ppData, uStart, uMid - 1, CompareFunc);
          }
       
          if ( uEnd > uMid )
          {
              QuickSort(ppData, uMid + 1, uEnd, CompareFunc);
         }
      }
       
      先测试一下这个快速排序算法排一百万个随机整数所花的时间:
      voidTest_QuickSort(void)
      {
          UINTi;
          UINTuCount = 1000000; //1000000
       
          srand(time(NULL));
          void **pp = (void **)malloc(uCount * sizeof(void *));
          for ( i = 0; i < uCount; i++ )
          {
              pp[i] = (void *)(rand() % uCount);
          }
       
             clock_tt1 = clock();
          QuickSort(pp, 0, uCount-1, UIntCompare);
             clock_tt2 = clock();
       
             printf("QuickSort 1000000 Time %ld\n", t2-t1);
       
          free(pp);
      }
       
      在双核CPU2.66GHZ机器上运行测试程序,打印出花费的时间约为406 ms
      在单核CPU2.4GHZ机器上运行测试程序,打印出花费时间约为484ms
      可见在双核CPU上运行单任务程序和单核CPU基本是一样的,效率没有任何提高。
       
      下面再来把上面的快速排序程序变成并行的,一个简单的方法就是将要排序的区间分成相同的几个段,然后对每个段进行快速排序,排序完后再使用归并算法将排好的几个区间归并成一个排好序的表,我们先四个线程来进行排序,代码如下:
       
      void ** Merge(void **ppData, UINTuStart, UINTuEnd,
             void **ppData2, UINTuStart2, UINTuEnd2, COMPAREFUNCcfunc)
      {
          UINTi, j, k;
          UINTu1, u2, v1,v2;
          void **pp1;
          void **pp2;
       
          void **pp = (void **)malloc( (uEnd-uStart+1+uEnd2-uStart2+1) * sizeof(void *));
          if ( pp == NULL )
          {
              returnNULL;
          }
       
          if ( (*cfunc)(ppData2[uStart2], ppData[uStart]) > 0 )
          {
              u1 = uStart;
              u2 = uEnd;
              v1 = uStart2;
              v2 = uEnd2;
              pp1 = ppData;
              pp2 = ppData2;
          }
          else
          {       
              u1 = uStart2;
              u2 = uEnd2;
              v1 = uStart;
              v2 = uEnd;
              pp1 = ppData2;
              pp2 = ppData;
          }
       
          k = 0;
          pp[k] = pp1[u1];
          j = v1;
          for (i = u1+1; i <= u2; i++ )
          {
              while ( j <= v2 )
              {
                  if ( (*cfunc)(pp2[j], pp1[i]) < 0 )
                 {
                      ++k;
                      pp[k] = pp2[j];
                      j++;
                  }
                  else
                  {
                      break;
                  }
              }
              ++k;
              pp[k] = pp1[i];
          }
       
          if ( j < v2 )
          {
              for ( i = j; i <= v2; i++)
              {
                  ++k;
                  pp[k] = pp2[i];
              }
          }
          returnpp;
      }
       
      typedefstructSORTNODE_st {
             void **           ppData;
             UINT             uStart;
             UINT             uEnd;
             COMPAREFUNCfunc;
      } SORTNODE;
       
       
      DWORDWINAPIQuickSort_Thread(void *arg)
      {
             SORTNODE   *pNode = (SORTNODE *)arg;
             QuickSort(pNode->ppData, pNode->uStart, pNode->uEnd, pNode->func);
             return 1;
      }
       
      #define THREAD_COUNT    4
       
      INTMQuickSort(void **ppData, UINTuStart, UINTuEnd,
      COMPAREFUNCCompareFunc)
      {
          void **pp1;
          void **pp2;
          void **pp3;
             INT               i;
             SORTNODE   Node[THREAD_COUNT];
             HANDLE        hThread[THREAD_COUNT];
       
             INT        nRet = CAPI_FAILED;
       
             for ( i = 0; i < THREAD_COUNT; i++)
             {
                    Node[i].ppData = ppData;
                    if ( i == 0 )
                    {
                           Node[i].uStart = uStart;
                    }
                    else
                    {
                           Node[i].uStart = uEnd * i /THREAD_COUNT + 1; 
                    }
                    Node[i].uEnd = uEnd *(i+1) / THREAD_COUNT;
                    Node[i].func = CompareFunc;
       
                    hThread[i] = CreateThread(NULL, 0, QuickSort_Thread, &(Node[i]), 0, NULL);
             }
       
             for ( i = 0; i < THREAD_COUNT; i++ )
             {
                    WaitForSingleObject(hThread[i], INFINITE);
             }
       
       
          pp1 = Merge(ppData, uStart, uEnd/4, ppData, uEnd/4+1, uEnd/2, CompareFunc);
       
          pp2 = Merge(ppData, uEnd/2+1, uEnd*3/4, ppData, uEnd*3/4+1, uEnd, CompareFunc);
       
          if ( pp1 != NULL && pp2 != NULL )
          {
              pp3 = Merge(pp1, 0, uEnd/2-uStart, pp2, 0, uEnd - uEnd/2 - 1, CompareFunc);
       
              if ( pp3 != NULL )
              {
                  UINTi;
               
                  for ( i = uStart; i <= uEnd; i++)
                  {
                      ppData[i] = pp3[i-uStart];
                  }
                  free(pp3);
                  nRet = CAPI_SUCCESS;
              }
          }
          if( pp1 != NULL)
          {
              free( pp1 );
          }
          if ( pp2 != NULL )
          {
              free( pp2 );
          }
       
          returnnRet;
      }
       
      用下面程序来测试一下排1百万个随机整数的花费时间:
      voidTest_MQuickSort (void)
      {
          UINTi;
          UINTuCount = 1000000; //1000
       
          srand(time(NULL));
          void **pp = (void **)malloc(uCount * sizeof(void *));
          for ( i = 0; i < uCount; i++ )
          {
              pp[i] = (void *)(rand() % uCount);
          }
       
             clock_tt1 = clock();
          INTnRet = MQuickSort(pp, 0, uCount-1, UIntCompare);
             clock_tt2 = clock();
       
             printf("MQuickSort 1000000 Time %ld\n", t2-t1);
       
          free(pp);
      }
       
      在双核CPU上运行后,打印出花费的时间为 234 ms , 单任务版的快速排序函数约需406ms左右,并行运行效率为:406/(2×234) = 86.7% 左右。运行速度快了172ms。
       
      可见双核CPU中,多任务程序速度还是有很大提高的。
       
      当然上面的多任务版的快速排序程序还有很大的改进余地,当对4个区间排好序后,后面的归并操作都是在一个任务里运行的,对整体效率会产生影响。估计将程序继续优化后,速度还能再快一些。
       

      发表于 @ 2006年08月23日 20:38:00|评论(loading...)|编辑

      新一篇: OpenMP并行程序设计(一) | 旧一篇: 《多任务下的数据结构与算法》一书中的红黑树的测试代码,供读者参考!

      评论

      #abenking 发表于2006-08-23 21:13:00  IP: 58.61.171.*
      任务切换这么耗费时间。双核CPU的出现,速度上又有一次飞跃。硬件的变化,软件技术也会随之有一个巨大的变化。呵呵。。
      #drzhouweiming 发表于2006-08-25 16:33:00  IP: 58.251.102.*
      不是任务切换费时间,而是代码中本身有一部分是单任务执行的。
      另外改写成多任务后,比单任务版的排序在单核机上的总时间本身要多。

      估计双核CPU的本身任务切换等开销应该小于10%
      #abenking 发表于2006-08-27 13:06:00  IP: 59.40.90.*
      我没有说清楚.我想说的是,单核CPU的任务切换原来这么耗时..
      #keke 发表于2006-09-01 14:36:00  IP: 218.18.39.*
      顶.看来多核是很有前途.

      现在是硬件的飞越变化,

      同时需要在软件里也要有一个体现.
      #w2001 发表于2007-12-07 20:13:04  IP: 218.94.6.*
      呵呵,周老师这个例子本身数据相关性就不是很大吧,没有数据相关性的多核并行基本上可以不考虑任务切换影响的,所以多核才会有那么好的效果。
      发表评论  


      当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
      Csdn Blog version 3.1a
      Copyright © 周伟明