使用google-perftools进行C/C++性能分析

安装libunwind


wget https://github.com/libunwind/libunwind/releases/download/v1.3.0/libunwind-1.3.0.tar.gz --no-check-certificate

tar -xvf libunwind-1.3.0.tar.gz

cd libunwind-1.3.0

./configure

make & make install

 

安装perftool


git clone https://github.com/gperftools/gperftools

cd gperftools/

sh autogen.sh

./configure

make & make install

ln -s /usr/local/lib/libprofiler.so.0 /usr/lib64/libprofiler.so.0 (64位机,32位目录在/usr/lib/)

 

安装graphviz

yum -y install graphviz

 

修改编译选项,增加“-L/usr/local/lib -lprofiler”

在性能评测点前运行:ProfilerStart(“MyProfile”)

在性能评测点后运行:ProfilerStop()

以上两个命令,可以直接写在代码里,也可以通过gdb call

 

目录检查,发现:MyProfile文件

pprof –svg ./myapp MyProfile > profile.svg

其他选项可以直接执行pprof查看,可通过多种形式查看报告,我们这里选择svg,svg可使用浏览器打开

__thread,记一次不成功的socket连接

背景:公司某产品自动更新特征库需求,创建临时线程,通过socket建链并下载更新特征库,前期这个需求是同事做的,由于方案问题,做了一部分做不下去了抛给了我
基于openstack的底层重度封装产品,不同头文件引用,暴露到产品层的也有多套socket连接(呵呵)
某某头文件里是:

#ifndef socket
#define socket xx_socket
#endif

又或是某某头文件里面写的:

int socket(int domain, int type, int protocol);

引用到不同头文件,又是截然不同的结果,网络经过封装,底层看不到需要使用的逻辑IP, <sys/socket.h>中的socket行不通,需要使用xx封装的xx_socket,经过尝试后,当调用到xx_socket后发现进程出现段错误复位,调用栈中的函数代码不可见,排查入参无异常,disass反汇编该调用函数和其他已有函数,xx_socket跳转的地址相同,排除引用错误的原因。
会看调用栈,栈顶函数getCompCSI(),获取组件CSI编码,有可能是线程级变量存储,gdb断点组件流程开线程之前,p getCompCSI(),结果返回正常,进入临时线程中继续p,引发复位,问题定位,线程级变量在新开线程没有初始化原因导致。

__thread

引用gcc.gnu.org中的介绍:

5.48 Thread-Local Storage

Thread-local storage (TLS) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread. The run-time model GCC uses to implement this originates in the IA-64 processor-specific ABI, but has since been migrated to other processors as well. It requires significant support from the linker (ld), dynamic linker (ld.so), and system libraries (libc.so and libpthread.so), so it is not available everywhere.

At the user level, the extension is visible with a new storage class keyword: __thread. For example:

     __thread int i;
     extern __thread struct state s;
     static __thread char *p;

The __thread specifier may be used alone, with the extern or static specifiers, but with no other storage class specifier. When used with extern or static, __thread must appear immediately after the other storage class specifier.

The __thread specifier may be applied to any global, file-scoped static, function-scoped static, or static data member of a class. It may not be applied to block-scoped automatic or non-static data member.

When the address-of operator is applied to a thread-local variable, it is evaluated at run-time and returns the address of the current thread’s instance of that variable. An address so obtained may be used by any thread. When a thread terminates, any pointers to thread-local variables in that thread become invalid.

No static initialization may refer to the address of a thread-local variable.

In C++, if an initializer is present for a thread-local variable, it must be a constant-expression, as defined in 5.19.2 of the ANSI/ISO C++ standard.

一个简单的用例,自己跑下它:

#include <stdio.h>
#include <pthread.h>

__thread int iTestVal = 1;

void* thread1(void *arg)
{
        printf("thread1, iTestVal = %d\n", iTestVal);
        iTestVal = 2;
        sleep(1);
        printf("thread1, after delay iTestVal = %d\n", iTestVal);
}

void* thread2(void *arg)
{
        printf("thread2, iTestVal = %d\n", iTestVal);
        sleep(1);
        printf("thread2, after delay iTestVal = %d\n", iTestVal);
}


int main()
{
        pthread_t pid1, pid2;
        pthread_create(&pid1, NULL, thread1, NULL);
        pthread_create(&pid2, NULL, thread2, NULL);
        pthread_join(pid1, NULL);
        pthread_join(pid2, NULL);

        return 0;
}

结果:

[root@TubbyFlashy-VM test]# gcc -lpthread main.c 
[root@TubbyFlashy-VM test]# ./a.out 
thread2, iTestVal = 1
thread1, iTestVal = 1
thread2, after delay iTestVal = 1
thread1, after delay iTestVal = 2

C语言程序设计之学生成绩管理系统

系统设计综述
题目
学生信息管理系统模拟
功能
该系统能够模拟学生基本信息管理。
成绩评定
整个系统开发分为三个部分,总分20分,如果有缺勤情况,每缺勤一次扣1分,上不封顶。
整体要求
? 该系统应具有合理的界面设计,并易于操作;
? 编码风格良好;
? 该系统用控制台程序即可实现;
? 编程语言为C语言,编程环境为VC++ 6.0

第一部分 存储结构设计
任务
设计学生结构体。
编程要求
1. 结构体设计
“学生”结构体包含“学号”、“姓名”、“性别”、“英语成绩”、“C语言成绩”。
2. 存储结构要求
在实现各个模块的功能时, 根据该模块的具体要求确定存储结构。
第二部分 菜单(界面)设计
任务
编程实现系统的菜单
编程要求
“登陆”菜单(选做,有加分)
1———-用户登陆
0———-退出系统
主菜单样式如下:
1———-学生录入
2———-学生浏览
3———-学生查询
4———-学生删除
5———-成绩统计
0———-退出系统
第三部分 功能和函数设计
任务
通过函数完成各个菜单模块的功能,要求合理设计主函数和各个子函数,合理设计各个函数之间的调用关系。
编程要求
1. 主函数:显示主菜单。
2. 如果设计并编写登陆菜单,要求合理设计登陆界面,要求用户输入用户名和密码,如果全都正确则进入主菜单,如果有一项不对,系统再提供两次机会输入,三次都错退出系统。(此部分有加分)
3. 编写函数完成“学生录入”功能,要求能将用户由键盘输入的若干学生信息追加到student.txt或student.dat中,存储结构可以使用数组,也可以使用链表。
4. 编写函数完成“学生浏览”功能,要求能将student.txt或student.dat文件中的全部学生信息显示出来,存储结构可以使用数组,也可以使用链表。
5. 编写函数完成“学生查询”功能,要求能按照学号或姓名对学生进行查询。
6. 编写函数完成“学生删除”功能,要求按照学号或姓名将某个学生删除,并将删除后的结果写回到文件中,此功能要求存储结构必须使用链表。
7. 设计并编写编写函数完成“成绩统计”功能,可以对“英语成绩”、“C语言成绩”进行单科浏览(降序排列),按某个学生统计总分和平均分,按英语和C语言两科成绩对学生进行排序。
第四部分 进度要求
? 进度要求
第2教学周——第3教学周:完成第一部分、第二部分以及第三部分的“学生录入”、“学生查询”和“学生浏览”功能。
第4教学周——第5教学周:完成“学生删除”和“成绩统计”功能。
第6教学周:教师完成对学生程序的考核

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<io.h>
FILE *file;
char user[25],pwd[25];
typedef struct student
{
char num[12];
char name[24];
char sex[8];
int score_eng;
int score_com;
struct student *next;
struct student *last;
}stu;
void setnewuser()   //创建新管理员用户
{
char username[25],pwd[25],repwd[25];
while(1){
printf("您是第一次访问本系统,需要创建一个管理员用户,n");
printf("请输入用户名:n");
gets(username);
printf("请输入密码:n");
gets(pwd);
printf("请再次输入密码:n");
gets(repwd);
if(strcmp(pwd,repwd)==0)
{
printf("创建成功!n");
file=fopen("student.dat","w");
fprintf(file,"%s %sn",username,pwd);
fclose(file);
return;
}
else
{
system("cls");
printf("两次输入密码不同,请重试!n");
}
}
}
int login()  //登录接口主程序
{
int t,select;
char checkuser[25],checkpwd[25];
system("cls");
while(1)
{
printf("请选择您的操作!n");
printf("1.登陆n");
printf("0.退出n");
scanf("%d",&select);
getchar();
if(select==0) return 0;
else if(select==1) break;
system("cls");
printf("录入有误,请重试!n");
}
system("cls");
printf("请登录!n");
printf("请输入用户名:n");
file=fopen("student.dat","r");
fscanf(file,"%s %s",user,pwd);
fclose(file);
gets(checkuser);

for(t=1;t<=3;t++)
{
printf("请输入密码:n");
gets(checkpwd);
if(strcmp(user,checkuser)==0&&strcmp(pwd,checkpwd)==0)
{
system("cls");
printf("登陆成功!n");
return 1;
}
printf("密码错误!n");
}
printf("密码错误次数过多,系统将退出!");
return 0;
}
void insert()
{
char num[12],name[25],sex[8];
int score_eng,score_com,select;
file=fopen("student.dat","at");
while(1)
{
system("cls");
printf("请输入学生数据(学号,姓名,性别,英语成绩,C语言成绩),空缺用0补位n");
scanf("%s %s %s %d %d",num,name,sex,&score_eng,&score_com);
getchar();
fprintf(file,"%s %s %s %d %dn",num,name,sex,score_eng,score_com);
system("cls");
printf("操作成功!n");
while(1)
{
printf("1.继续添加数据n");
printf("0.返回主菜单n");
scanf("%d",&select);
getchar();
if(select==1) break;
else if(select==0)
{
system("cls");
fclose(file);
return;
}
else
{
system("cls");
printf("输入的选项有误,请重新输入!n");
}
}
}
}

void view()
{
char num[12],name[25],sex[8],tmp[50];
int score_eng,score_com;
getchar();
system("cls");
file=fopen("student.dat","r");
printf("学号t姓名tt性别t英语tC语言n");
fgets(tmp,50,file);  //过滤首行用户名密码
while(fscanf(file,"%s %s %s %d %d",num,name,sex,&score_eng,&score_com)!=EOF)
printf("%st%stt%st%dt%dn",num,name,sex,score_eng,score_com);
fclose(file);
system("pause");
system("cls");
}
void find()
{
char num[12],name[25],sex[8],tmp[50];
int score_eng,score_com;
stu *head=NULL,*p;
system("cls");
printf("请输入学号或姓名!n");
file=fopen("student.dat","r");
fgets(tmp,50,file);
scanf("%s",tmp);
getchar();
printf("学号t姓名tt性别t英语tC语言n");
while(fscanf(file,"%s %s %s %d %d",num,name,sex,&score_eng,&score_com)!=EOF)
{
if(strcmp(tmp,num)==0||strcmp(tmp,name)==0)
printf("%st%stt%st%dt%dn",num,name,sex,score_eng,score_com);

}
system("pause");
system("cls");
fclose(file);
}
void del()
{
char num_tmp[12],name_tmp[25],sex_tmp[8],tmp[50];
int score_eng_tmp,score_com_tmp,key=0;
stu *head=NULL,*p,*last_tmp=NULL;
system("cls");
file=fopen("student.dat","r");
getchar();
fgets(tmp,50,file);
printf("请输入要删除的学号或姓名:n");
scanf("%s",tmp);
while(fscanf(file,"%s %s %s %d %d",num_tmp,name_tmp,sex_tmp,&score_eng_tmp,&score_com_tmp)!=EOF)
{
if(strcmp(tmp,num_tmp)==0||strcmp(tmp,name_tmp)==0)
{
key++;
continue;
}

p=(stu *)malloc(sizeof(stu));
p->next=head;
if(p->next!=NULL) p->next->last=p;
head=p;
strcpy(p->num,num_tmp);
strcpy(p->name,name_tmp);
strcpy(p->sex,sex_tmp);
p->score_eng=score_eng_tmp;
p->score_com=score_com_tmp;
}
p->last=NULL;
if(key==0)
{
system("cls");
printf("未找到您要找的信息!n");
system("pause");
system("cls");
getchar();
return;
}
file=fopen("student.dat","w");
fprintf(file,"%s %sn",user,pwd);
while(p->next!=NULL) p=p->next;
while(p!=NULL)
{
fprintf(file,"%s %s %s %d %dn",p->num,p->name,p->sex,p->score_eng,p->score_com);
p=p->last;
}
fclose(file);
getchar();
printf("操作完成!n");
system("pause");
system("cls");
}
void rankbyeng(stu *head)
{
char num_tmp[12],name_tmp[25],sex_tmp[8],tmp[50];
int score_eng_tmp,score_com_tmp;
stu *i,*j;
i=head;
while(i!=NULL)
{
j=i->next;
while(j!=NULL)
{
if(i->score_eng<j->score_eng)
{
strcpy(num_tmp,i->num);
strcpy(name_tmp,i->name);
strcpy(sex_tmp,i->sex);
score_eng_tmp=i->score_eng;
score_com_tmp=i->score_com;
strcpy(i->num,j->num);
strcpy(i->name,j->name);
strcpy(i->sex,j->sex);
i->score_eng=j->score_eng;
i->score_com=j->score_com;
strcpy(j->num,num_tmp);
strcpy(j->name,name_tmp);
strcpy(j->sex,sex_tmp);
j->score_eng=score_eng_tmp;
j->score_com=score_com_tmp;
}
j=j->next;
}
i=i->next;
}
}

void rankbycom(stu *head)
{
char num_tmp[12],name_tmp[25],sex_tmp[8],tmp[50];
int score_eng_tmp,score_com_tmp;
stu *i,*j;
i=head;
while(i!=NULL)
{
j=i->next;
while(j!=NULL)
{
if(i->score_com<j->score_com)
{
strcpy(num_tmp,i->num);
strcpy(name_tmp,i->name);
strcpy(sex_tmp,i->sex);
score_eng_tmp=i->score_eng;
score_com_tmp=i->score_com;
strcpy(i->num,j->num);
strcpy(i->name,j->name);
strcpy(i->sex,j->sex);
i->score_eng=j->score_eng;
i->score_com=j->score_com;
strcpy(j->num,num_tmp);
strcpy(j->name,name_tmp);
strcpy(j->sex,sex_tmp);
j->score_eng=score_eng_tmp;
j->score_com=score_com_tmp;
}
j=j->next;
}
i=i->next;
}
}
void rankbyall(stu *head)
{
char num_tmp[12],name_tmp[25],sex_tmp[8],tmp[50];
int score_eng_tmp,score_com_tmp;
stu *i,*j;
i=head;
while(i!=NULL)
{
j=i->next;
while(j!=NULL)
{
if((i->score_eng+i->score_com)<(j->score_eng+j->score_com))
{
strcpy(num_tmp,i->num);
strcpy(name_tmp,i->name);
strcpy(sex_tmp,i->sex);
score_eng_tmp=i->score_eng;
score_com_tmp=i->score_com;
strcpy(i->num,j->num);
strcpy(i->name,j->name);
strcpy(i->sex,j->sex);
i->score_eng=j->score_eng;
i->score_com=j->score_com;
strcpy(j->num,num_tmp);
strcpy(j->name,name_tmp);
strcpy(j->sex,sex_tmp);
j->score_eng=score_eng_tmp;
j->score_com=score_com_tmp;
}
j=j->next;
}
i=i->next;
}
}
void statistics()
{
char num_tmp[12],name_tmp[25],sex_tmp[8],tmp[50];
int score_eng_tmp,score_com_tmp,select;
stu *head=NULL,*p;
system("cls");
file=fopen("student.dat","r");
getchar();
fgets(tmp,50,file);
while(fscanf(file,"%s %s %s %d %d",num_tmp,name_tmp,sex_tmp,&score_eng_tmp,&score_com_tmp)!=EOF)
{
p=(stu *)malloc(sizeof(stu));
p->next=head;
head=p;
strcpy(p->num,num_tmp);
strcpy(p->name,name_tmp);
strcpy(p->sex,sex_tmp);
p->score_eng=score_eng_tmp;
p->score_com=score_com_tmp;
p=head;

}
fclose(file);
system("cls");
printf("1.按英语成绩排序n");
printf("2.按C语言成绩排序n");
printf("3.按平均成绩排序n");
scanf("%d",&select);
switch (select)
{
case 1: rankbyeng(head); break;
case 2: rankbycom(head); break;
case 3: rankbyall(head); break;
default: printf("输入错误!n"); return;
}
system("cls");
getchar();
printf("学号t姓名tt性别t英语tC语言n");
while(p!=NULL)
{
printf("%st%stt%st%dt%dn",p->num,p->name,p->sex,p->score_eng,p->score_com);
p=p->next;
}
system("pause");
system("cls");
}

int main()
{
char select;
if(access("student.dat",0))
setnewuser();
if (login()==0) return 0;

while(1)
{
printf("请输入操作序号!n");
printf("1.学生录入n");
printf("2.学生浏览n");
printf("3.学生查询n");
printf("4.学生删除n");
printf("5.数据统计n");
printf("0.退出系统n");
select=getchar();
switch (select)
{
case '1': insert();break;
case '2': view(); break;
case '3': find(); break;
case '4': del(); break;
case '5': statistics(); break;
case '0': return 0;
default :
system("cls");
printf("输入错误!,请重新输入!n");
}
}
return 0;
}

C语言中malloc的用法

Malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。

原型:extern void *malloc(unsigned int num_bytes);

包含头文件stdlib.h   malloc.h

在用malloc开辟数组空间时,使用 p=(char *)malloc(t*sizeof(char));开辟t个元素的数组空间,

发现sizeof (p)只有4个字节,是因为,sizeof(p)计算出来的是p指针的大小而不是开辟空间的大小。

void free(void *FirstByte);

在malloc分配空间用后,应该用free()释放分配的内存

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *p; //      本意是想建立char p[100];的数组,但是却不能等同于p[100];
int t,len;
scanf(“%d”,&t);
p=(char *)malloc(t*sizeof(char));

if(p==NULL) return 0;   //如果内存分配失败,退出程序
memset(p,’a’,t*sizeof(char));   //实际建立的大小虽为sizeof(char)*t,若要使用sizeof(p)只能计算出p指针的大小
p[t-1]=’�’;
puts(p);
printf(“%xn”,p);
free(p);     // 用后释放空间
return 0;
}