Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3926764
  • 博文数量: 93
  • 博客积分: 3189
  • 博客等级: 中校
  • 技术积分: 4229
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-02 13:29
个人简介

出没于杭州和青岛的程序猿一枚,对内核略懂一二

文章分类

全部博文(93)

文章存档

2016年(2)

2015年(3)

2014年(11)

2013年(29)

2012年(16)

2011年(5)

2010年(5)

2009年(22)

分类: LINUX

2014-04-16 11:12:45

这里以多线程操作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


阅读(9308) | 评论(2) | 转发(2) |
给主人留下些什么吧!~~

瀚海书香2014-07-01 14:13:15

linux_fresher:博主的测试不科学阿,难道原子操作的性能还是不如mutex么

atomic 是最下面一条线,耗费时间最小,性能最高的。不知道你是怎么看出来原子操作的性能不如mutex的。

回复 | 举报

linux_fresher2014-06-30 20:53:16

博主的测试不科学阿,难道原子操作的性能还是不如mutex么