File: active_memory.c

package info (click to toggle)
nws 2.11-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,700 kB
  • ctags: 2,820
  • sloc: ansic: 28,849; sh: 3,289; java: 1,205; makefile: 697; perl: 12
file content (399 lines) | stat: -rwxr-xr-x 10,527 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/* $Id: active_memory.c,v 1.16 2003/10/17 22:30:07 graziano Exp $ */

#include "config_nws.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#include "diagnostic.h"
#include "memory.h"
#include "nws_sensor.h"
#include "active_memory_custom.h"

#define READ_END 0
#define WRITE_END 1

int ActiveCpuGetLoad(unsigned short niceValue,
		     unsigned int maxWait,
		     unsigned int testLength,
		     double *available);
int PassiveCpuCloseMonitor(void);
int PassiveCpuGetLoad(int resource,
		      unsigned short niceValue,
		      double *newFraction,
		      double *existingFraction);
int PassiveCpuMonitorAvailable(void);
int PassiveCpuOpenMonitor(int sleeptime);

typedef struct bulk {
  char * ptr;
  struct bulk * next;
  int length;
} Bulk;

extern int errno;

#ifdef MEMORY_SUPPORT
static int BaseMem = 0;
static int cpu_monitor_on = 0;
static unsigned long CountFromLastCalibration = 0;
static unsigned long CountBetweenCalibration = INIT_COUNT_BETWEEN_CALIBRATION;
#endif

/* Compute the total amount of physical memory used 
   as the sum of the resident size of each process.
   this function parses the output of "PS PS_ARGS" */
unsigned int 
ActiveMemoryGetUsed(void) {

  FILE *file;
  char command[128];
  char string[4096];
  char *token;
  unsigned int field_status, field_rss, memory_used;
  unsigned int index_token, status_valid, rss_value;
  
  strcpy(command, PS);
  strcat(command, " ");
  strcat(command, PS_ARGS);
  if ((file = popen(command, "r")) != NULL) {
    field_status = 0;
    field_rss = 0;
    memory_used = 0;
    while ((field_status == 0) || (field_rss == 0)) {
      if (fgets(string, sizeof(string), file) != NULL) {
		token = strtok(string, PS_DELIM);
		index_token = 1;
		while (token != NULL) {
		  if ((field_status == 0) && (strcmp(token, STATUS_FIELD) == 0)) {
			field_status = index_token;
		  }
		  if ((field_rss == 0) && (strcmp(token, RSS_FIELD) == 0))
			field_rss = index_token;
		  index_token++;
		  token = strtok(NULL, PS_DELIM);
		}
      }
	  else {
         break;
	  }
    }
    
    if ((field_status == 0) || (field_rss == 0))
      FAIL3("ActiveMemoryGetUsed: Error in reading (%s): "
	    "unable to find the fields %s and %s\n",
	    command, STATUS_FIELD, RSS_FIELD);
    
    memory_used = 0;
    
    while (fgets(string, sizeof(string), file) != NULL) {
      token = strtok(string, PS_DELIM);
      index_token = 1;
      status_valid = 0;
      while (token != NULL) {
	if (index_token == field_status) 
	  if (strpbrk(token, STATUS_VALID) != NULL)
	    status_valid = 1;
	if ((status_valid) && (index_token == field_rss)) {
	  if (sscanf(token, "%u", &rss_value) != 1) {
	    FAIL3("ActiveMemoryGetUsed: Error in reading (%s) from (%s):"
		  "no valid RSS value in (%s)\n",
		  command, string, token);
	  }
	  else
		memory_used += rss_value*MEMSOR_UNIT;
	}
	index_token++;
	token = strtok(NULL, PS_DELIM);
      }
    }
      
    pclose(file);
  } else
    FAIL2("ActiveMemoryGetUsed: execution of %s failed (error %d)\n",
          command, errno);

  return memory_used;
}


#if 0
/* Try to get a good rough estimate of the free memory
   to speed up the calibration process */
static unsigned int
ActiveMemoryGetRoughlyFree(void) {

  FILE * file;
  char command[128];
  char string[4096];
  char * token;
  unsigned int field_free, memory_free;
  unsigned int index_token, free_value;

  strcpy(command, VMSTAT);
  if (strstr(command, "vmstat") == NULL)
    return 0;
  strcat(command, " 1 2");
  field_free = 0;
  if ((file = popen(command, "r")) != NULL) {
    while (field_free == 0) {
      if (fgets(string, sizeof(string), file) != NULL) {
        token = strtok(string, VMSTAT_DELIM);
        index_token = 1;
        while ((token != NULL) && (field_free == 0))  {
          if ((field_free ==0) && (strcmp(token, VMSTAT_FREE) == 0))
            field_free = index_token;
          index_token++;
          token = strtok(NULL, VMSTAT_DELIM);
        }
      }
	  else {
		break;
	  }
    }

    if (field_free == 0)
      FAIL2("ActiveMemoryGetRoughlyFree: Error in reading (%s): "
            "unable to find the field %s\n",
            command, VMSTAT_FREE);
 
    memory_free = 0;
    free_value = 0;
    sleep(1);
 
    while (fgets(string, sizeof(string), file) != NULL) {
      token = strtok(string, VMSTAT_DELIM);
      index_token = 1;
      while (token != NULL) {
        if (index_token == field_free) {
          if (sscanf(token, "%u", &free_value) != 1) {
            FAIL3("ActiveMemoryGetRoughlyFree: Error in reading (%s) from (%s):"
                  "no valid FREE value in (%s)\n",
                  command, string, token);
          } else
            memory_free = free_value*MEMSOR_UNIT;
        }
        index_token++;
        token = strtok(NULL, VMSTAT_DELIM);
      }
    }

    pclose(file);
  } else
    FAIL2("ActiveMemoryGetRoughlyFree: execution of %s failed (error %d)\n",
          command, errno);

  return memory_free;
}
#endif


/* this code returns the ammount of physical memory available 
   computed as the base memory minus the memory used at this time */
int
ActiveMemoryGetFree(double *measure) {
 
#ifdef MEMORY_SUPPORT
  unsigned int usedmem;
  int freemem;
  double current, available;

    DDEBUG3("ActiveMemoryGetFree: basemem = %d, count = %d, max = %d\n",
	    BaseMem,CountFromLastCalibration,CountBetweenCalibration);
  
  if (BaseMem == 0)
    ActiveMemoryMonitorCalibration();
  
  if (CountFromLastCalibration > CountBetweenCalibration) {
    if (cpu_monitor_on) {
      if (PassiveCpuGetLoad(0, 0, &available, &current)) {
		  DDEBUG1("ActiveMemoryGetFree: Passive cpu load=%f\n", current);
		if (current >= MIN_CPU_FOR_CALIBRATION) {
		  if (ActiveCpuGetLoad(19, 20, 500, &available)) {
			  DDEBUG1("ActiveMemoryGetFree: Active cpu load=%f\n", available);
			if (available >= MIN_CPU_FOR_CALIBRATION) {
			  if (PassiveCpuCloseMonitor())
				cpu_monitor_on = 0;
			  ActiveMemoryMonitorCalibration();
			  CountFromLastCalibration = 0;
			  if (CountBetweenCalibration < MAX_COUNT_BETWEEN_CALIBRATION)
				CountBetweenCalibration *= 2;
			}
		  }
		  else
			LOG("ActiveMemoryGetFree: error getting an active cpu measurement\n");
		}
      }
	  else
		LOG("ActiveMemoryGetFree: error getting a passive cpu measurement\n");  
    }
	else
      if (!PassiveCpuMonitorAvailable)
		CountFromLastCalibration = 0;
      else 
		if (PassiveCpuOpenMonitor(20))
		  cpu_monitor_on = 1;
		else
		  LOG("ActiveMemoryGetFree: problem starting passive CPU sensor\n");
  }
  else {
    if ((CountFromLastCalibration > CountBetweenCalibration - 16)
		&& (!cpu_monitor_on)
		&& (PassiveCpuMonitorAvailable)) {
      if (PassiveCpuOpenMonitor(20)) {
		cpu_monitor_on = 1;
      }
	  else {
		LOG("ActiveMemoryGetFree: problem starting passive CPU sensor\n");
	  }
	}
  }
  usedmem = ActiveMemoryGetUsed();
  freemem = BaseMem - usedmem;
  
  if (freemem < 0) {
    FAIL2("ActiveMemoryGetFree: Base memory size to small :"
	  "base=%d and memory in used=%d\n", BaseMem, usedmem);
  }

  usedmem = usedmem / 1024;
  freemem = freemem / 1024;

    DDEBUG2("ActiveMemoryGetFree: %d MBytes physical memory available (%d MBytes used)\n", freemem, usedmem);

  *measure = freemem;
  CountFromLastCalibration++;
  
  return(1);
#else
  return 0;
#endif

}


int
ActiveMemoryMonitorAvailable(void) {
#ifdef MEMORY_SUPPORT
	return 1;
#else
	return 0;
#endif
}


/* a calibration is needed to compute the maximum ammount
   of memory available on this machine. It allocates step
   by step CALIBRATION_BULK_SIZE of memory and ask the sensor to give
   the ammount of memory used by the application. When this ammount of
   used memory does not grow any more, we have reached the top. */

int
ActiveMemoryMonitorCalibration(void) {

#ifdef MEMORY_SUPPORT
  unsigned int i, page_size, used, max_used, stop_count, base_start;
  struct bulk *start, *current;
  int connection[2];
  pid_t childPid;
 
  if(pipe(connection) != 0) {
      FAIL("ActiveMemoryMonitorCalibration: pipe() failed\n");
    }

  childPid = fork();

  if(childPid < 0) {
      FAIL("ActiveMemoryMonitorCalibration: fork() failed\n");
  }
  else if(childPid > 0) {
    /* Parent process. */
    close(connection[WRITE_END]);
    read(connection[READ_END], &BaseMem, sizeof(int));
    close(connection[READ_END]);
    wait(NULL);
    return 1;
  }

  /* Child comes here. */
  BaseMem = 0;
  close(connection[READ_END]);
  nice(19);
  LOG("ActiveMemoryMonitorCalibration: start calibration\n");
  page_size = getpagesize();
  base_start = ActiveMemoryGetRoughlyFree()*CALIBRATION_SPEEDUP_RATIO; 
        DDEBUG1("Calibration speedup : start from %d KB of base memory\n", base_start);

  start = (struct bulk *)malloc(sizeof(struct bulk));
  if (start == NULL) {
    write(connection[WRITE_END], &BaseMem, sizeof(int));
    close(connection[WRITE_END]);
    exit(0);
  }
  start->ptr = calloc(base_start*1024,sizeof(char));
  if (start->ptr == NULL) {
    free(start);
    write(connection[WRITE_END], &BaseMem, sizeof(int));
    close(connection[WRITE_END]);
    exit(0);
  } 
  start->length = base_start*1024*sizeof(char);
  start->next = NULL;

  used = 99;
  for (i=0; i<start->length; i+=page_size)
    start->ptr[i] = (int)used;
  start->ptr[start->length-1] = (int)used;
  
  current = start;
  max_used = 0;
  stop_count = 0;
  used = 1;
  while (stop_count <ITERATIONS_STALLED) {
    current->next = (struct bulk *)malloc(sizeof(struct bulk));
    if (current->next == NULL)
      break;
    current = current->next;
    current->ptr = malloc(CALIBRATION_BULK_SIZE*sizeof(char));
    if (current->ptr == NULL) {
      stop_count++;
      continue;
    }
    current->length = CALIBRATION_BULK_SIZE*sizeof(char);
    current->next = NULL;
    
    for (i=0; i<current->length; i+=page_size)
      current->ptr[i] = (int)used;
    current->ptr[current->length-1] = (int)used;
    
    used = ActiveMemoryGetUsed();
    if (used > max_used)
      max_used = used;
    else
      stop_count++;
  }
  
  BaseMem = max_used;
	DDEBUG1("Calibration done : %d KB of base memory\n", BaseMem);

  current = start;
  while (current != NULL) {
     free(current->ptr);
    current = current->next;
  }
  LOG1("ActiveMemoryMonitorCalibration: end of calibration (%d KB)\n",
       BaseMem);
  write(connection[WRITE_END], &BaseMem, sizeof(int));
  close(connection[WRITE_END]);
  exit(0); 
#else
  return 0;
#endif

}