A new user interface for you! Read more...

File getdelays-compat.diff of Package delayacct-utils

--- delayacct-utils-0.3/getdelays.c.orig	2007-08-22 15:07:18.000000000 +0200
+++ delayacct-utils-0.3/getdelays.c	2007-10-22 17:04:39.195544000 +0200
@@ -8,7 +8,7 @@
  * Copyright (c) Jay Lan, SGI. 2006
  *
  * Compile with
- *	gcc -I/usr/src/linux/include getdelays.c -o getdelays
+ *	gcc -I/usr/src/linux/include -Os -Wall getdelays.c -o getdelays
  *
  * This program is derived from getdelays.c in the Linux kernel source
  * and so the kernel license applies.
@@ -182,7 +182,7 @@ int get_family_id(int sd)
 		char buf[256];
 	} ans;
 
-	int id, rc;
+	int id = -1, rc;
 	struct nlattr *na;
 	int rep_len;
 
@@ -206,6 +206,51 @@ int get_family_id(int sd)
 
 void print_delayacct(struct taskstats *t)
 {
+	struct taskstats *oldt = t;
+	PRINTF("taskstats version %i (compiled for %i)\n", 
+		t->version, TASKSTATS_VERSION);
+	/* Someone extended struct taskstat in an incompatible way from
+	 * version 1 to 2. Version 1 had 
+	 *	__u16 version; 
+	 *	__u16 padding[3];
+	 *	__u64 cpu_count;
+	 * which puts cpu_count at offset 8. Version 2 had
+	 *	__u16 version;
+ 	 * 	__u32 ac_exitcode;
+	 *	__u8  ac_flag;
+	 *	__u8  ac_nice;
+	 *	__u64 cpu_count;
+	 * and the author surely assumed that this put cpu_count also at
+	 * offset 8. Wrong; it's at offset 16 (on 64bit architectures),
+	 * as the ac_exitcode is naturally aligned at offset 4, not 2, without
+	 * using the __attribute__((packed)). Version 4 has
+	 *	...
+	 *	__u64 cpu_count __attribute__((aligned(8)));
+	 * to enforce the alignment to offset 16 even on 32bit archs, so
+	 * we're at least consistent, but the interface changed yet another
+	 * time on 32bit archs ...
+	 * Oh well, a lesson in basic C programming would have avoided this
+	 * whole mess. garloff@suse.de, 2007-10-22 
+	 */
+#if TASKSTATS_VERSION == 1		/* gcc assumes offset 8 */
+	if (t->version >= 4)		/* real offset is 16 */
+		t = (struct taskstats*) ((char*)t + 8);	
+	else if (t->version > 1)	/* real offset is 12/16 */
+		t = (struct taskstats*) ((char*)t + sizeof(void*));
+#elif TASKSTATS_VERSION < 4		/* gcc assumes offset 12/16 */
+	if (t->version >= 4 && sizeof(void*) < 8)	/* real 16/16 */
+		t = (struct taskstats*) ((char*)t + 4);
+	else if (t->version <= 1)	/* real 8 */
+		t = (struct taskstats*) ((char*)t - sizeof(void*));
+#else					/* gcc assumes offset 16 */
+	if (t->version <= 1)		/* real 8 */
+		t = (struct taskstats*) ((char*)t - 8);
+	else if (t->version < 4 && sizeof(void*) < 8)	/* real 12/16 */
+		t = (struct taskstats*) ((char*)t - 4);
+#endif
+	if (t != oldt)
+		PRINTF("Fixup: taskstat %p -> %p\n", oldt, t);
+
 	printf("\n\nCPU   %15s%15s%15s%15s\n"
 	       "      %15llu%15llu%15llu%15llu\n"
 	       "IO    %15s%15s\n"
@@ -222,16 +267,37 @@ void print_delayacct(struct taskstats *t
 
 void print_ioacct(struct taskstats *t)
 {
+	/* TODO: The offsets of these fields have also changed
+	 * on 32bit architectures due to the alignment fixes in
+	 * version 4.
+	 */
+	int samever = 0;
+	if ( (sizeof(void*) == 8) ||
+	   ( (TASKSTATS_VERSION < 4) == (t->version < 4) ) )
+		   samever = 1;
+#ifdef TASKSTATS_HAS_IO_ACCOUNTING
+	if (t->version >= 3 && samever)
 	printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
 		t->ac_comm,
 		(unsigned long long)t->read_bytes,
 		(unsigned long long)t->write_bytes,
 		(unsigned long long)t->cancelled_write_bytes);
+	else
+#endif
+#if TASKSTATS_VERSION >= 2
+	if (t->version >= 2 && samever)
+	printf("%s: readchar=%llu, writechar=%llu\n",
+		t->ac_comm,
+		(unsigned long long)t->read_char,
+		(unsigned long long)t->write_char);
+	else
+#endif
+	printf("no io stats available\n");
 }
 
 int main(int argc, char *argv[])
 {
-	int c, rc, rep_len, aggr_len, len2, cmd_type;
+	int c, rc, rep_len, aggr_len, len2, cmd_type = -1;
 	__u16 id;
 	__u32 mypid;
 
@@ -367,7 +433,7 @@ int main(int argc, char *argv[])
 			goto done;
 		}
 
-		PRINTF("nlmsghdr size=%d, nlmsg_len=%d, rep_len=%d\n",
+		PRINTF("nlmsghdr size=%zd, nlmsg_len=%d, rep_len=%d\n",
 		       sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);