File: procinterrupts.c

package info (click to toggle)
irqbalance 0.12-7etch1
  • links: PTS
  • area: main
  • in suites: etch
  • size: 180 kB
  • ctags: 54
  • sloc: ansic: 493; sh: 94; xml: 31; makefile: 10
file content (179 lines) | stat: -rw-r--r-- 4,817 bytes parent folder | download
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
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>



#include "prototypes.h"

/*
   Copyright (C) 2003 Red Hat, Inc. All rights reserved.
                                                                                                             
   Usage and distribution of this file are subject to the Open Software License version 2.1
   that can be found at http://www.opensource.org/licenses/osl-2.1.txt and the COPYING file as
   distributed together with this file is included herein by reference. Alternatively you can use 
   and distribute this file under version 1.1 of the same license.
                                                                                                                      
   Author: Arjan van de Ven   <arjanv@redhat.com>

*/

/*
 * This file contains the code that deals with the /proc/interrupts file and updating the
 * counts in the interrupts[] array.
 */


/* characters should remain in the parsed lines */
#define validchars "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-/"

/*
 * Calculate irq delta and reset the cpu for the distribution code to start working from
 * a clean slate.
 * In addition this cleans up the counts so that the next run starts fresh. 
 */
static void post_process_interrupts(int calcdelta)
{
	int i;
	for (i = 0; i < MAX_INTERRUPTS ; i++) {
		/* 
		 * use a running average for the delta to smoothen out peaks, and more 
		 * importantly, avoid short periods of inactivity to have too much effect.
		 */
		 
		if (calcdelta)		
			interrupts[i].delta = interrupts[i].delta/3 + 
			 	interrupts[i].count -  interrupts[i].oldcount;
		interrupts[i].oldcpu =  interrupts[i].cpu;
		interrupts[i].oldcount =interrupts[i].count;
		interrupts[i].count = 0;
		interrupts[i].cpu = MAX_CPU; /* none */
	}
}

static void reset_interrupt_info(void)
{
	int i;
	for (i = 0; i < MAX_INTERRUPTS ; i++) {
		 interrupts[i].count = 0;
		 interrupts[i].oldcount = 0;
		 interrupts[i].oldcpu = 0;
		 interrupts[i].cpu = MAX_CPU; /* all/none */
		 interrupts[i].type = IRQ_INACTIVE;
		 interrupts[i].number = i;
	}
}

int parse_proc_interrupts(int incremental) 
{
	FILE *file;
	char linebuffer[1024];
	
	file = fopen("/proc/interrupts","r");
	assert(file != NULL);
	/* first line is useless */
	fgets(linebuffer, 1024, file);
	
	if (!incremental)
		reset_interrupt_info();
	
	while (!feof(file)) {
		char *cursor, *word;
		int column = 0;
		int irqnumber = 0;
		fgets(linebuffer, 1024, file);
		if (strlen(linebuffer)==0)
			continue;
		/* squash all unwanted characters */
		word = cursor = linebuffer;
		while (cursor) {
			char *word;
			long long count;
			
			word = strsep(&cursor, " ");
			
			if (!strlen(word))
				continue;
				
		
			/* first column is the irq number */	
			if (column==0) {
				int ret;
				ret = sscanf(word,"%i",&irqnumber);
				if (!ret)  /* non numeric end stuff */
					irqnumber = MAX_INTERRUPTS-1; 
				/* This version of irqbalance cannot handle interrups larger
				 * than 255, so skip stuff right here.  Newer versions
				 * have replaced the length limited array with a list,
				 * so this limitation is no longer present in say 0.55.
				 * Also see http://bugs.debian.org/500985
				 */
				if (irqnumber < 0 || irqnumber >= MAX_INTERRUPTS)
					break;
			/* then N columns of counts, where N is the number of cpu's */
			} else if (column <= cpucount) {
				sscanf(word,"%lli",&count);
				interrupts[irqnumber].count += count;
			/* and lastly the names of the drivers */
			} else if ( ( (incremental==0) || (interrupts[irqnumber].type==IRQ_INACTIVE) ) 
							&& column>cpucount+1)
				classify_type(irqnumber, word);
			column++;
		}
	}
	
	fclose(file);
	post_process_interrupts(incremental);	
	return 0;
}

/* 
 * Write a selected configuration back to the kernel to activate the new settings 
 */
void activate_irqtable(void)
{
	int i;
	FILE *file;
	char filename[256];
	for (i = 0; i < MAX_INTERRUPTS; i++) {
		/* shortcut: if old and new cpu are identical, don't do a thing */
		if (interrupts[i].oldcpu == interrupts[i].cpu)
			continue;
		if (interrupts[i].type == IRQ_INACTIVE)
			continue;
		snprintf(filename,255,"/proc/irq/%i/smp_affinity",i);
		file = fopen(filename, "w");
		if (file==NULL)
			continue;
		if (interrupts[i].cpu < MAX_CPU)
			fprintf(file,"%x",1<<interrupts[i].cpu);
		else
			fprintf(file,"ffffffff");
		fclose(file);	
	}
}

/* 
 * Read the current configuration back from the kernel 
 */
int get_current_irqcpu(int irq)
{
	unsigned int i;
	FILE *file;
	char filename[256];
	
	snprintf(filename,255,"/proc/irq/%i/smp_affinity",irq);
	file = fopen(filename, "r");
	if (file==NULL)
		return 0;
	if (fscanf(file, "%x", &i)<1) 
		return 0;
	fclose(file);	
	i = ffs(i);
	
	if ( (i>0) && (i<=MAX_CPU) )
		return i-1;
	else
		return 0;
}