sigar 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }