1 /*
2  * Copyright (c) 2008, XenSource Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of XenSource Inc. nor the names of its contributors
13  *       may be used to endorse or promote products derived from this software
14  *       without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #ifndef __TAP_PROFILE_H__
30 #define __TAP_PROFILE_H__
31 
32 #ifndef _GNU_SOURCE
33   #define _GNU_SOURCE
34 #endif
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <sys/time.h>
42 #include <time.h>
43 #include <fcntl.h>
44 #include <inttypes.h>
45 
46 //#define PROFILING
47 //#define LOGGING
48 
49 #define TAPPROF_IN  1
50 #define TAPPROF_OUT 2
51 
52 struct profile_times {
53 	char    *fn_name;
54 	uint64_t in, out_sum, cnt;
55 };
56 
57 struct profile_info {
58 	FILE                 *log;
59 	int                   size;
60 	char                 *name;
61 	unsigned long long    seq;
62 	struct profile_times *pt;
63 };
64 
65 #ifdef PROFILING
66 
67 static inline void
tp_open(struct profile_info * prof,char * tap_name,char * log_name,int size)68 tp_open(struct profile_info *prof, char *tap_name, char *log_name, int size)
69 {
70 	memset(prof, 0, sizeof(struct profile_info));
71 #ifdef LOGGING
72 	prof->log  = fopen(log_name, "w");
73 #endif
74 	prof->size = size;
75 	prof->name = strdup(tap_name);
76 	prof->pt   = malloc(sizeof(struct profile_times) * prof->size);
77 	if (prof->pt)
78 		memset(prof->pt, 0, sizeof(struct profile_times) * prof->size);
79 }
80 
81 static inline void
tp_close(struct profile_info * prof)82 tp_close(struct profile_info *prof)
83 {
84 	int i;
85 	struct profile_times *pt;
86 
87 	for (i = 0; i < prof->size; i++) {
88 		pt = &prof->pt[i];
89 		if (pt->fn_name) {
90 			syslog(LOG_DEBUG, "%s: %s: cnt: %llu, avg time: %llu\n",
91 			       prof->name, pt->fn_name, pt->cnt,
92 			       ((pt->cnt) ? (pt->out_sum / pt->cnt) : 0));
93 			free(pt->fn_name);
94 		}
95 	}
96 
97 #ifdef LOGGING
98 	if (prof->log)
99 		fclose(prof->log);
100 #endif
101 	free(prof->name);
102 	if (prof->pt)
103 		free(prof->pt);
104 }
105 
106 static inline u64
tp_get_id(struct profile_info * prof)107 tp_get_id(struct profile_info *prof)
108 {
109 	return prof->seq++;
110 }
111 
112 static inline int
tp_fn_id(struct profile_info * prof,const char * name)113 tp_fn_id(struct profile_info *prof, const char *name)
114 {
115 	int i;
116 	struct profile_times *pt;
117 
118 	for (i = 0; i < prof->size; i++) {
119 		pt = &prof->pt[i];
120 		if (!pt->fn_name)
121 			return i;
122 		if (!strcmp(pt->fn_name, name))
123 			return i;
124 	}
125 
126 	return prof->size - 1;
127 }
128 
129 static inline void
__tp_in(struct profile_info * prof,const char * func)130 __tp_in(struct profile_info *prof, const char *func)
131 {
132 	long long _time;
133 	int idx = tp_fn_id(prof, func);
134 	struct profile_times *pt = &prof->pt[idx];
135 
136 	if (!pt->fn_name)
137 		pt->fn_name = strdup(func);
138 
139 	asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
140 	pt->in = _time;
141 }
142 
143 #define tp_in(prof) __tp_in(prof, __func__)
144 
145 static inline void
__tp_out(struct profile_info * prof,const char * func)146 __tp_out(struct profile_info *prof, const char *func)
147 {
148 	long long _time;
149 	int idx = tp_fn_id(prof, func);
150 	struct profile_times *pt = &prof->pt[idx];
151 
152 	if (!pt->fn_name || !pt->in)
153 		return;
154 
155 	asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
156 	pt->cnt++;
157 	pt->out_sum += (_time - pt->in);
158 	pt->in       = 0;
159 }
160 
161 #define tp_out(prof) __tp_out(prof, __func__)
162 
163 static inline void
__tp_log(struct profile_info * prof,u64 id,const char * func,int direction)164 __tp_log(struct profile_info *prof, u64 id, const char *func, int direction)
165 {
166 	long long _time;
167 	asm volatile(".byte 0x0f, 0x31" : "=A" (_time));
168 
169 	if (direction == TAPPROF_IN)
170 		__tp_in(prof, func);
171 	else
172 		__tp_out(prof, func);
173 
174 #ifdef LOGGING
175         if (prof->log)
176 	        fprintf(prof->log, "%s: %s: %llu, %lld\n", func,
177 			((direction == TAPPROF_IN) ? "in" : "out"), id, _time);
178 #endif
179 }
180 
181 #define tp_log(prof, id, direction) __tp_log(prof, id, __func__, direction)
182 
183 #else
184 #define tp_open(prof, tname, lname, size)  ((void)0)
185 #define tp_close(prof)                     ((void)0)
186 #define tp_in(prof)                        ((void)0)
187 #define tp_out(prof)                       ((void)0)
188 #define tp_log(prof, sec, direction)       ((void)0)
189 #endif
190 
191 #endif
192