sigar 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,6 +30,11 @@
30
30
  #ifndef WIN32
31
31
  #include <arpa/inet.h>
32
32
  #endif
33
+ #if defined(HAVE_UTMPX_H)
34
+ # include <utmpx.h>
35
+ #elif defined(HAVE_UTMP_H)
36
+ # include <utmp.h>
37
+ #endif
33
38
 
34
39
  #include "sigar.h"
35
40
  #include "sigar_private.h"
@@ -59,6 +64,7 @@ SIGAR_DECLARE(int) sigar_open(sigar_t **sigar)
59
64
  (*sigar)->net_listen = NULL;
60
65
  (*sigar)->net_services_tcp = NULL;
61
66
  (*sigar)->net_services_udp = NULL;
67
+ (*sigar)->proc_io = NULL;
62
68
  }
63
69
 
64
70
  return status;
@@ -91,6 +97,11 @@ SIGAR_DECLARE(int) sigar_close(sigar_t *sigar)
91
97
  if (sigar->net_services_udp) {
92
98
  sigar_cache_destroy(sigar->net_services_udp);
93
99
  }
100
+ if (sigar->proc_io) {
101
+ sigar_cache_destroy(sigar->proc_io);
102
+ }
103
+
104
+
94
105
 
95
106
  return sigar_os_close(sigar);
96
107
  }
@@ -118,7 +129,7 @@ SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
118
129
  int status;
119
130
 
120
131
  if (!sigar->proc_cpu) {
121
- sigar->proc_cpu = sigar_cache_new(128);
132
+ sigar->proc_cpu = sigar_expired_cache_new(128, PID_CACHE_CLEANUP_PERIOD, PID_CACHE_ENTRY_EXPIRE_PERIOD);
122
133
  }
123
134
 
124
135
  entry = sigar_cache_get(sigar->proc_cpu, pid);
@@ -167,6 +178,106 @@ SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid,
167
178
 
168
179
  return SIGAR_OK;
169
180
  }
181
+ void copy_cached_disk_io_into_disk_io( sigar_cached_proc_disk_io_t *cached, sigar_proc_disk_io_t *proc_disk_io) {
182
+ proc_disk_io->bytes_read = cached->bytes_read_diff;
183
+ proc_disk_io->bytes_written = cached->bytes_written_diff;
184
+ proc_disk_io->bytes_total = cached->bytes_total_diff;
185
+ }
186
+
187
+ sigar_uint64_t get_io_diff(sigar_uint64_t current_value, sigar_uint64_t prev_value, sigar_uint64_t time_diff) {
188
+ double io_diff;
189
+ sigar_uint64_t int_io_diff;
190
+ if ( current_value == SIGAR_FIELD_NOTIMPL ) {
191
+ return SIGAR_FIELD_NOTIMPL;
192
+ }
193
+ io_diff = (( current_value - prev_value)/(double)time_diff)*SIGAR_MSEC;
194
+ int_io_diff = (sigar_uint64_t)io_diff;
195
+ if (int_io_diff >=0) {
196
+ return int_io_diff;
197
+ }
198
+ return 0;
199
+ }
200
+
201
+ void calculate_io_diff(sigar_proc_cumulative_disk_io_t * proc_disk_io, sigar_cached_proc_disk_io_t *cached, sigar_uint64_t time_diff, int is_first_time) {
202
+ /*calculate avg diff /read/write/total per second*/
203
+ if (!is_first_time) {
204
+ cached->bytes_written_diff = get_io_diff(proc_disk_io->bytes_written, cached->bytes_written, time_diff);
205
+ cached->bytes_read_diff = get_io_diff(proc_disk_io->bytes_read, cached->bytes_read, time_diff);
206
+ cached->bytes_total_diff = get_io_diff(proc_disk_io->bytes_total, cached->bytes_total, time_diff);
207
+ }
208
+ else {
209
+ cached->bytes_total_diff = cached->bytes_read_diff = cached->bytes_written_diff = 0.0;
210
+ }
211
+ // now put in cache the current cumulative values
212
+ cached->bytes_written = proc_disk_io->bytes_written;
213
+ cached->bytes_read = proc_disk_io->bytes_read;
214
+ cached->bytes_total = proc_disk_io->bytes_total;
215
+ }
216
+
217
+ SIGAR_DECLARE(int) sigar_proc_disk_io_get(sigar_t *sigar, sigar_pid_t pid,
218
+ sigar_proc_disk_io_t *proc_disk_io)
219
+ {
220
+ sigar_cache_entry_t *entry;
221
+ sigar_cached_proc_disk_io_t *prev;
222
+ sigar_proc_cumulative_disk_io_t cumulative_proc_disk_io;
223
+ sigar_uint64_t time_now = sigar_time_now_millis();
224
+ sigar_uint64_t time_diff;
225
+ int status, is_first_time;
226
+
227
+ if (!sigar->proc_io) {
228
+ sigar->proc_io = sigar_expired_cache_new(128, PID_CACHE_CLEANUP_PERIOD, PID_CACHE_ENTRY_EXPIRE_PERIOD);
229
+ }
230
+
231
+ entry = sigar_cache_get(sigar->proc_io, pid);
232
+ if (entry->value) {
233
+ prev = (sigar_cached_proc_disk_io_t *)entry->value;
234
+ }
235
+ else {
236
+ prev = entry->value = malloc(sizeof(*prev));
237
+ SIGAR_ZERO(prev);
238
+ }
239
+ is_first_time = (prev->last_time == 0);
240
+ time_diff = time_now - prev->last_time;
241
+
242
+ if (time_diff < 1000) {
243
+ /* we were just called within < 1 second ago. */
244
+ copy_cached_disk_io_into_disk_io(prev, proc_disk_io);
245
+ if (time_diff < 0) {
246
+ // something is wrong at least from now on the time will be ok
247
+ prev->last_time = time_now;
248
+ }
249
+ return SIGAR_OK;
250
+ }
251
+ prev->last_time = time_now;
252
+
253
+
254
+ status =
255
+ sigar_proc_cumulative_disk_io_get(sigar, pid,
256
+ &cumulative_proc_disk_io);
257
+
258
+ if (status != SIGAR_OK) {
259
+ return status;
260
+ }
261
+ calculate_io_diff(&cumulative_proc_disk_io, prev, time_diff, is_first_time);
262
+ copy_cached_disk_io_into_disk_io(prev, proc_disk_io);
263
+ return SIGAR_OK;
264
+ }
265
+
266
+ void get_cache_info(sigar_cache_t * cache, char * name){
267
+ if (cache == NULL) {
268
+ return;
269
+ }
270
+
271
+ printf("******** %s *********\n", name);
272
+ sigar_cache_dump(cache);
273
+ }
274
+
275
+ SIGAR_DECLARE(int) sigar_dump_pid_cache_get(sigar_t *sigar, sigar_dump_pid_cache_t *info) {
276
+
277
+ get_cache_info(sigar->proc_cpu, "proc cpu cache");
278
+ get_cache_info(sigar->proc_io, "proc io cache");
279
+ return SIGAR_OK;
280
+ }
170
281
 
171
282
  SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
172
283
  sigar_proc_stat_t *procstat)
@@ -1024,40 +1135,7 @@ SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar,
1024
1135
  return SIGAR_OK;
1025
1136
  }
1026
1137
 
1027
- #ifdef DARWIN
1028
- #include <AvailabilityMacros.h>
1029
- #endif
1030
- #ifdef MAC_OS_X_VERSION_10_5
1031
- # if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1032
- # define SIGAR_NO_UTMP
1033
- # endif
1034
- /* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */
1035
- #endif
1036
-
1037
- #if defined(__sun)
1038
- # include <utmpx.h>
1039
- # define SIGAR_UTMP_FILE _UTMPX_FILE
1040
- # define ut_time ut_tv.tv_sec
1041
- #elif defined(WIN32)
1042
- /* XXX may not be the default */
1043
- #define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp"
1044
- #define UT_LINESIZE 16
1045
- #define UT_NAMESIZE 16
1046
- #define UT_HOSTSIZE 256
1047
- #define UT_IDLEN 2
1048
- #define ut_name ut_user
1049
-
1050
- struct utmp {
1051
- short ut_type;
1052
- int ut_pid;
1053
- char ut_line[UT_LINESIZE];
1054
- char ut_id[UT_IDLEN];
1055
- time_t ut_time;
1056
- char ut_user[UT_NAMESIZE];
1057
- char ut_host[UT_HOSTSIZE];
1058
- long ut_addr;
1059
- };
1060
- #elif defined(NETWARE)
1138
+ #if defined(NETWARE)
1061
1139
  static char *getpass(const char *prompt)
1062
1140
  {
1063
1141
  static char password[BUFSIZ];
@@ -1067,109 +1145,48 @@ static char *getpass(const char *prompt)
1067
1145
 
1068
1146
  return (char *)&password;
1069
1147
  }
1070
- #elif !defined(SIGAR_NO_UTMP)
1071
- # include <utmp.h>
1072
- # ifdef UTMP_FILE
1073
- # define SIGAR_UTMP_FILE UTMP_FILE
1074
- # else
1075
- # define SIGAR_UTMP_FILE _PATH_UTMP
1076
- # endif
1077
- #endif
1078
-
1079
- #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN)
1080
- # define ut_user ut_name
1081
- #endif
1082
-
1083
- #ifdef DARWIN
1084
- /* XXX from utmpx.h; sizeof changed in 10.5 */
1085
- /* additionally, utmpx does not work on 10.4 */
1086
- #define SIGAR_HAS_UTMPX
1087
- #define _PATH_UTMPX "/var/run/utmpx"
1088
- #define _UTX_USERSIZE 256 /* matches MAXLOGNAME */
1089
- #define _UTX_LINESIZE 32
1090
- #define _UTX_IDSIZE 4
1091
- #define _UTX_HOSTSIZE 256
1092
- struct utmpx {
1093
- char ut_user[_UTX_USERSIZE]; /* login name */
1094
- char ut_id[_UTX_IDSIZE]; /* id */
1095
- char ut_line[_UTX_LINESIZE]; /* tty name */
1096
- pid_t ut_pid; /* process id creating the entry */
1097
- short ut_type; /* type of this entry */
1098
- struct timeval ut_tv; /* time entry was created */
1099
- char ut_host[_UTX_HOSTSIZE]; /* host name */
1100
- __uint32_t ut_pad[16]; /* reserved for future use */
1101
- };
1102
- #define ut_xtime ut_tv.tv_sec
1103
- #define UTMPX_USER_PROCESS 7
1104
- /* end utmpx.h */
1105
- #define SIGAR_UTMPX_FILE _PATH_UTMPX
1106
1148
  #endif
1107
1149
 
1108
- #if !defined(NETWARE) && !defined(_AIX)
1109
-
1110
1150
  #define WHOCPY(dest, src) \
1111
1151
  SIGAR_SSTRCPY(dest, src); \
1112
1152
  if (sizeof(src) < sizeof(dest)) \
1113
1153
  dest[sizeof(src)] = '\0'
1114
1154
 
1115
- #ifdef SIGAR_HAS_UTMPX
1116
- static int sigar_who_utmpx(sigar_t *sigar,
1117
- sigar_who_list_t *wholist)
1155
+ static int sigar_who_utmp(sigar_t *sigar,
1156
+ sigar_who_list_t *wholist)
1118
1157
  {
1119
- FILE *fp;
1120
- struct utmpx ut;
1158
+ #if defined(HAVE_UTMPX_H)
1159
+ struct utmpx *ut;
1121
1160
 
1122
- if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) {
1123
- return errno;
1124
- }
1161
+ setutxent();
1125
1162
 
1126
- while (fread(&ut, sizeof(ut), 1, fp) == 1) {
1163
+ while ((ut = getutxent()) != NULL) {
1127
1164
  sigar_who_t *who;
1128
1165
 
1129
- if (*ut.ut_user == '\0') {
1166
+ if (*ut->ut_user == '\0') {
1130
1167
  continue;
1131
1168
  }
1132
1169
 
1133
- #ifdef UTMPX_USER_PROCESS
1134
- if (ut.ut_type != UTMPX_USER_PROCESS) {
1170
+ if (ut->ut_type != USER_PROCESS) {
1135
1171
  continue;
1136
1172
  }
1137
- #endif
1138
1173
 
1139
1174
  SIGAR_WHO_LIST_GROW(wholist);
1140
1175
  who = &wholist->data[wholist->number++];
1141
1176
 
1142
- WHOCPY(who->user, ut.ut_user);
1143
- WHOCPY(who->device, ut.ut_line);
1144
- WHOCPY(who->host, ut.ut_host);
1177
+ WHOCPY(who->user, ut->ut_user);
1178
+ WHOCPY(who->device, ut->ut_line);
1179
+ WHOCPY(who->host, ut->ut_host);
1145
1180
 
1146
- who->time = ut.ut_xtime;
1181
+ who->time = ut->ut_tv.tv_sec;
1147
1182
  }
1148
1183
 
1149
- fclose(fp);
1150
-
1151
- return SIGAR_OK;
1152
- }
1153
- #endif
1154
-
1155
- #if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX)
1156
- #define sigar_who_utmp sigar_who_utmpx
1157
- #else
1158
- static int sigar_who_utmp(sigar_t *sigar,
1159
- sigar_who_list_t *wholist)
1160
- {
1184
+ endutxent();
1185
+ #elif defined(HAVE_UTMP_H)
1161
1186
  FILE *fp;
1162
- #ifdef __sun
1163
- /* use futmpx w/ pid32_t for sparc64 */
1164
- struct futmpx ut;
1165
- #else
1166
1187
  struct utmp ut;
1167
- #endif
1168
- if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) {
1169
- #ifdef SIGAR_HAS_UTMPX
1170
- /* Darwin 10.5 */
1171
- return sigar_who_utmpx(sigar, wholist);
1172
- #endif
1188
+
1189
+ if (!(fp = fopen(_PATH_UTMP, "r"))) {
1173
1190
  return errno;
1174
1191
  }
1175
1192
 
@@ -1189,7 +1206,7 @@ static int sigar_who_utmp(sigar_t *sigar,
1189
1206
  SIGAR_WHO_LIST_GROW(wholist);
1190
1207
  who = &wholist->data[wholist->number++];
1191
1208
 
1192
- WHOCPY(who->user, ut.ut_user);
1209
+ WHOCPY(who->user, ut.ut_name);
1193
1210
  WHOCPY(who->device, ut.ut_line);
1194
1211
  WHOCPY(who->host, ut.ut_host);
1195
1212
 
@@ -1197,11 +1214,10 @@ static int sigar_who_utmp(sigar_t *sigar,
1197
1214
  }
1198
1215
 
1199
1216
  fclose(fp);
1217
+ #endif
1200
1218
 
1201
1219
  return SIGAR_OK;
1202
1220
  }
1203
- #endif /* SIGAR_NO_UTMP */
1204
- #endif /* NETWARE */
1205
1221
 
1206
1222
  #if defined(WIN32)
1207
1223
 
@@ -35,7 +35,7 @@ static void free_value(void *ptr)
35
35
  free(ptr);
36
36
  }
37
37
 
38
- sigar_cache_t *sigar_cache_new(int size)
38
+ sigar_cache_t *sigar_expired_cache_new(int size, sigar_uint64_t cleanup_period_millis, sigar_uint64_t entry_expire_period)
39
39
  {
40
40
  sigar_cache_t *table = malloc(sizeof(*table));
41
41
  table->count = 0;
@@ -43,16 +43,27 @@ sigar_cache_t *sigar_cache_new(int size)
43
43
  table->entries = malloc(ENTRIES_SIZE(size));
44
44
  memset(table->entries, '\0', ENTRIES_SIZE(size));
45
45
  table->free_value = free_value;
46
+ table->cleanup_period_millis = cleanup_period_millis;
47
+ table->last_cleanup_time = sigar_time_now_millis();
48
+ table->entry_expire_period = entry_expire_period;
46
49
  return table;
47
50
  }
48
51
 
49
- #ifdef DEBUG_CACHE
52
+ sigar_cache_t *sigar_cache_new(int size)
53
+ {
54
+ return sigar_expired_cache_new(size, SIGAR_FIELD_NOTIMPL, SIGAR_FIELD_NOTIMPL);
55
+ }
56
+
57
+
58
+ /*#ifdef DEBUG_CACHE*/
50
59
  /* see how well entries are distributed */
51
- static void sigar_cache_dump(sigar_cache_t *table)
60
+ void sigar_cache_dump(sigar_cache_t *table)
52
61
  {
53
62
  int i;
54
63
  sigar_cache_entry_t **entries = table->entries;
55
-
64
+ printf("table size %lu\n", (long)table->size);
65
+ printf("table count %lu\n", (long)table->count);
66
+
56
67
  for (i=0; i<table->size; i++) {
57
68
  sigar_cache_entry_t *entry = *entries++;
58
69
 
@@ -68,12 +79,12 @@ static void sigar_cache_dump(sigar_cache_t *table)
68
79
  printf("\n");
69
80
  fflush(stdout);
70
81
  }
71
- #endif
82
+ /*#endif*/
72
83
 
73
84
  static void sigar_cache_rehash(sigar_cache_t *table)
74
85
  {
75
86
  int i;
76
- unsigned int new_size = table->size * 2 + 1;
87
+ unsigned int new_size = table->count * 2 + 1;
77
88
  sigar_cache_entry_t **entries = table->entries;
78
89
  sigar_cache_entry_t **new_entries =
79
90
  malloc(ENTRIES_SIZE(new_size));
@@ -101,16 +112,76 @@ static void sigar_cache_rehash(sigar_cache_t *table)
101
112
  #define SIGAR_CACHE_IX(t, k) \
102
113
  t->entries + (k % t->size)
103
114
 
115
+ void sigar_perform_cleanup_if_necessary(sigar_cache_t *table) {
116
+ sigar_uint64_t current_time;
117
+ int i;
118
+ sigar_cache_entry_t **entries;
119
+ if (table->cleanup_period_millis == SIGAR_FIELD_NOTIMPL) {
120
+ /* no cleanup for this cache) */
121
+ return;
122
+ }
123
+ current_time = sigar_time_now_millis();
124
+ if ((current_time - table->last_cleanup_time) < table->cleanup_period_millis) {
125
+ /* not enough time has passed since last cleanup */
126
+ return;
127
+ }
128
+
129
+ /* performing cleanup */
130
+ entries = table->entries;
131
+
132
+ table->last_cleanup_time = current_time;
133
+
134
+ for (i=0; i<table->size; i++) {
135
+ sigar_cache_entry_t *entry, *ptr, *entry_prev=NULL, **entry_in_table;
136
+ entry_in_table = entries;
137
+ entry = *entries++;
138
+
139
+ while (entry) {
140
+ sigar_uint64_t period_with_no_access = current_time - entry->last_access_time;
141
+ ptr = entry->next;
142
+ if (table->entry_expire_period < period_with_no_access) {
143
+ /* no one acess this entry for too long - we can delete it */
144
+ if (entry->value) {
145
+ table->free_value(entry->value);
146
+ }
147
+ free(entry);
148
+ table->count--;
149
+ if (entry_prev != NULL) {
150
+ entry_prev->next = ptr;
151
+ }
152
+ else {
153
+ /* removing first entry - head of list should point to next entry */
154
+ *entry_in_table = ptr;
155
+ }
156
+ }
157
+ else {
158
+ /* entry not expired - advance entry_prev to current entry*/
159
+ entry_prev = entry;
160
+ }
161
+ entry = ptr;
162
+ }
163
+ }
164
+ if (table->count < (table->size/4)) {
165
+ /* hash table (the array size) too big for the amount of values it contains perform rehash */
166
+ sigar_cache_rehash(table);
167
+ }
168
+ }
169
+
170
+
171
+
172
+
104
173
  sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table,
105
174
  sigar_uint64_t key)
106
175
  {
107
176
  sigar_cache_entry_t *entry, **ptr;
177
+ sigar_perform_cleanup_if_necessary(table);
108
178
 
109
179
  for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
110
180
  entry;
111
181
  ptr = &entry->next, entry = *ptr)
112
182
  {
113
183
  if (entry->id == key) {
184
+ entry->last_access_time = sigar_time_now_millis();
114
185
  return entry;
115
186
  }
116
187
  }
@@ -123,17 +194,19 @@ sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
123
194
  sigar_uint64_t key)
124
195
  {
125
196
  sigar_cache_entry_t *entry, **ptr;
197
+ sigar_perform_cleanup_if_necessary(table);
126
198
 
127
199
  for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
128
200
  entry;
129
201
  ptr = &entry->next, entry = *ptr)
130
202
  {
131
203
  if (entry->id == key) {
204
+ entry->last_access_time = sigar_time_now_millis();
132
205
  return entry;
133
206
  }
134
207
  }
135
208
 
136
- if (table->count++ > table->size) {
209
+ if (++table->count > table->size) {
137
210
  sigar_cache_rehash(table);
138
211
 
139
212
  for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr;
@@ -147,6 +220,7 @@ sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table,
147
220
  entry->id = key;
148
221
  entry->value = NULL;
149
222
  entry->next = NULL;
223
+ entry->last_access_time = sigar_time_now_millis();
150
224
 
151
225
  return entry;
152
226
  }