关于x86_64架构下atomic、mutex、rwlock的性能对比

1170阅读 0评论2014-09-23 embeddedlwp
分类:LINUX

这里以多线程操作long类型变量,进行加法运算1亿次的时间作为性能对比的标准。

测试使用SLES 11SP2操作系统,3.0.80内核,CPU使用Xeon 55062 socket, 4 cores, 1thread

由于针对64位类型的atomic glibc没有提供相应的库,将内核实现代码移植到应用层
atomic64.h

点击(此处)折叠或打开

  1. #ifndef __HI_ATOMIC64_H__
  2. #define __HI_ATOMIC64_H__
  3. #include <stdio.h>
  4. #include <getopt.h>
  5. #include <limits.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <pthread.h>
  10. #include <sys/time.h>
  11. #include <arpa/inet.h>
  12. #include <fcntl.h>
  13. #include <signal.h>
  14. #include <errno.h>
  15. #include <sys/time.h>



  16. /* Learn from kernel */
  17. #ifdef __x86_64__

  18. #define LOCK_PREFIX "lock ;"
  19. typedef struct {
  20.         long long counter;
  21. } atomic64_t;

  22. /**
  23.  * atomic64_read - read atomic64 variable
  24.  * @v: pointer of type atomic64_t
  25.  *
  26.  * Atomically reads the value of @v.
  27.  * Doesn't imply a read memory barrier.
  28.  */
  29. static inline long atomic64_read(const atomic64_t *v)
  30. {
  31.         return (*(volatile long *)&(v)->counter);
  32. }

  33. /**
  34.  * atomic64_set - set atomic64 variable
  35.  * @v: pointer to type atomic64_t
  36.  * @i: required value
  37.  *
  38.  * Atomically sets the value of @v to @i.
  39.  */
  40. static inline void atomic64_set(atomic64_t *v, long i)
  41. {
  42.         v->counter = i;
  43. }

  44. /**
  45.  * atomic64_add - add integer to atomic64 variable
  46.  * @i: integer value to add
  47.  * @v: pointer to type atomic64_t
  48.  *
  49.  * Atomically adds @i to @v.
  50.  */
  51. static inline void atomic64_add(long i, atomic64_t *v)
  52. {
  53.         asm volatile(LOCK_PREFIX "addq %1,%0"
  54.                      : "=m" (v->counter)
  55.                      : "er" (i), "m" (v->counter));
  56. }

  57. /**
  58.  * atomic64_sub - subtract the atomic64 variable
  59.  * @i: integer value to subtract
  60.  * @v: pointer to type atomic64_t
  61.  *
  62.  * Atomically subtracts @i from @v.
  63.  */
  64. static inline void atomic64_sub(long i, atomic64_t *v)
  65. {
  66.         asm volatile(LOCK_PREFIX "subq %1,%0"
  67.                      : "=m" (v->counter)
  68.                      : "er" (i), "m" (v->counter));
  69. }
  70. #else /* __x86_64__ */
  71. /*FIXME:
  72.  * This program will run on x86_64 machine in the expected future, we
  73.  * do _not_ need to care other cpu architecture.
  74.  */
  75. #endif

  76. #endif
测试代码performance.c

点击(此处)折叠或打开

  1. /*******************************************************************************

  2.   Copyright(c) 2008-2014

  3.   This program is free software; you can redistribute it and/or modify it
  4.   under the terms and conditions of the GNU General Public License,
  5.   version 2, as published by the Free Software Foundation.

  6.   This program is distributed in the hope it will be useful, but WITHOUT
  7.   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8.   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  9.   more details.

  10.   You should have received a copy of the GNU General Public License along with
  11.   this program; if not, write to the Free Software Foundation, Inc.,
  12.   51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  13.   The full GNU General Public License is included in this distribution in
  14.   the file called "COPYING".


  15.   Date: 2014-04-15 21:27:57 CST

  16.   Contact Information:
  17.   Tony <tingw.liu@gmail.com>
  18.   Home, Qingdao, China.
  19. *******************************************************************************/



  20. #include "atomic64.h"

  21. atomic64_t num;
  22. long mutexnum = 0;
  23. long maxnum;

  24. struct timeval tv;
  25. long starttime;

  26. //FIXME: gettimeofday is a non-thread safe sysycall
  27. static pthread_mutex_t timelock = PTHREAD_MUTEX_INITIALIZER;
  28. #define TIME_LOCK() pthread_mutex_lock(&timelock)
  29. #define TIME_UNLOCK() pthread_mutex_unlock(&timelock)

  30. static pthread_mutex_t numlock = PTHREAD_MUTEX_INITIALIZER;
  31. #define MUTEX_LOCK() pthread_mutex_lock(&numlock)
  32. #define MUTEX_UNLOCK() pthread_mutex_unlock(&numlock)

  33. static pthread_rwlock_t rwnumlock = PTHREAD_RWLOCK_INITIALIZER;
  34. #define RW_LOCK() pthread_rwlock_wrlock(&rwnumlock)
  35. #define RW_UNLOCK() pthread_rwlock_unlock(&rwnumlock);

  36. static void * add_func(void *arg)
  37. {
  38.         long stoptime;
  39.         while(1) {
  40.                 atomic64_add(1, &num);
  41.                 if (atomic64_read(&num) > maxnum) {
  42.                         TIME_LOCK();
  43.                         gettimeofday(&tv, 0);
  44.                         TIME_UNLOCK();
  45.                         stoptime= (long)tv.tv_sec * (long)1000000 +
  46.                                 (long)tv.tv_usec;
  47.                         printf("Used %ld microseconds\n", stoptime - starttime);
  48.                         break;
  49.                 }
  50.         }
  51. }


  52. static void *add_func_rwlock(void *arg)
  53. {
  54.         long stoptime;
  55.         while(1) {

  56.                 RW_LOCK();
  57.                 ++mutexnum;
  58.                 if (mutexnum > maxnum) {
  59.                         RW_UNLOCK();
  60.                         TIME_LOCK();
  61.                         gettimeofday(&tv, 0);
  62.                         TIME_UNLOCK();
  63.                         stoptime= (long)tv.tv_sec * (long)1000000 +
  64.                                 (long)tv.tv_usec;
  65.                         printf("Used %ld microseconds\n", stoptime - starttime);
  66.                         break;
  67.                 }
  68.                 RW_UNLOCK();
  69.         }
  70. }

  71. static void *add_func_mutex(void *arg)
  72. {
  73.         long stoptime;
  74.         while(1) {

  75.                 MUTEX_LOCK();
  76.                 ++mutexnum;
  77.                 if (mutexnum > maxnum) {
  78.                         MUTEX_UNLOCK();
  79.                         TIME_LOCK();
  80.                         gettimeofday(&tv, 0);
  81.                         TIME_UNLOCK();
  82.                         stoptime= (long)tv.tv_sec * (long)1000000 +
  83.                                 (long)tv.tv_usec;
  84.                         printf("Used %ld microseconds\n", stoptime - starttime);
  85.                         break;
  86.                 }
  87.                 MUTEX_UNLOCK();
  88.         }
  89. }

  90. #define ATOMIC_TYPE 0
  91. #define MUTEX_TYPE 1
  92. #define RW_TYPE 2
  93. int main(int argc, char **argv)
  94. {
  95.         pthread_t thread;
  96.         pthread_attr_t thread_attr;
  97.         int threadnum, i, type;
  98.         if (argc != 4) {
  99.                 printf("Usage: %s threadnum maxnum type[0-atomic, 1-mutex, 2-rwlock]\n",
  100.                                 argv[0]);
  101.                 exit(0);
  102.         }
  103.         threadnum = atoi(argv[1]);
  104.         maxnum = atoll(argv[2]);
  105.         type = atoi(argv[3]);
  106.         printf("Use %d threads add num from 0 to %ld\n", threadnum, maxnum);
  107.         gettimeofday(&tv, 0);
  108.         starttime= (long)tv.tv_sec * (long)1000000 + (long)tv.tv_usec;

  109.         atomic64_set(&num, 0);
  110.         pthread_attr_init(&thread_attr);
  111.         //pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
  112.         for (i = 0; i < threadnum; i++) {
  113.                 if (type == ATOMIC_TYPE)
  114.                         pthread_create(&thread, &thread_attr, add_func, 0);
  115.                 else if (type == MUTEX_TYPE)
  116.                         pthread_create(&thread, &thread_attr, add_func_mutex, 0);
  117.                 else if (type == RW_TYPE)
  118.                         pthread_create(&thread, &thread_attr, add_func_rwlock, 0);
  119.         }
  120.         while(1)
  121.                 sleep(10);
  122. }
运行结果这里就不详细列出来了,可以直接看这个曲线图。

横坐标是线程数,纵坐标是运算1亿次耗费的微秒数。
从这个图中可以看出,对于频繁写操作的情况atomic > mutex > rwlock
对于同一种同步类型,并不是随着线程数的增加而一直增加,不过因为只有8个核心,所以没有测试更多线程的情况。

欢迎转载,转载请注明出处:http://forever.blog.chinaunix.net


上一篇:ubuntu 12.04下如何将物理网卡加入bridge连接外网
下一篇:F2FS文件系统架构与原理分析(一)——设计背景与功能