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;
}
|