a small update: > 8245: 2.4.34 > 8237e: 2.6.21.1
I've tried the following setup: multicast stream @8192 kbps, one process taking in and dumping the data on each board [1]. a) 8245/2.4.34/e100: 2.3.43-k1, @400 MHz b) 8245/2.6.17/e100: 2.3.43-k1 [2] @350 MHz c) 8347e/2.6.21.1/gianfar @400 Mhz c) XScale-IXP42x/2.6.18-4/ixp4xx @266 MHz (NSLU2) (2.3.43-k1 is the e100 driver version). The process load for taking in the data is: a) 4-5% [3] b) 10-11% c) 13-14% d) 4-5% While the current 8347/gianfar platform is the worst performer, the 2.6 kernel with the 2.4 e100 (before the rewrite) seems to perform poorly too [4]. So the 834x preforms worse wrt the 8245 based configuration even though it is slightly higher clocked. It seems as if I bumped into the problem that lead me stick with the 2.4 in the first place for this 8245 platform; but never got round to investigating. I find these results especially intriguing when considering an ARM platform (NSLU2 device) that I had around, clocked at only 66% of the 8347 and at 80% of the 8245 performs certainly in par with the last one... Even though I will need to recheck this (results to follow), a quick test didn't reveal any significant difference between a ppc and powerpc arch in the kernel. It does look like, on our 8245/83xx platforms, the 2.6.x kernel performs worse wrt the 2.4 ppc kernels and the 83xx configuration is worse wrt the 8245 based configuration [5]. In retrospect, we had signals that there was a problem with the 8245/83xx performance over the network last year when investigating gstreamer, but due to time pressure but assumed it was due to gstreamer and not the processor. This came as a suprise to some of the ppl on the gstreamer mailing list that reported performant ports to ARM architectures. The results with the NSLU2 will certainly put heat on us from management when redesigning or for follow up designs :( Anyhow, I'm currently extending my test setups since this is an important problem and set back. If anyone has a hint to explaining what is going on here, please do since solving this will certainly beat redesigning (esp. considering the timeframe we've been assigned). I've only found one relevant reference to 2.4/2.6 network performance decrease at this point [6]. [1] sources attached mcrecv -p 225.1.2.3 -a 12345 mcsend -p 225.1.2.3 -a 12345 -b 8192 I'm preparing more tests in the next days, in trying to figure out what really is going on here. [2] 2.4 driver ported to 2.6 kernel. [3] This figure is read from top and not from the app since it seems to be an underestimate (./fs/proc/array.c). [4] I believe I ported the 2.4 e100 to the 2.6 2 years ago because it performed much better, but I'll verify that in the next days. [5] Obviously, testing 834x against the 2.4 kernel is not really an option :) [6] http://www.mail-archive.com/[EMAIL PROTECTED]/msg01283.html -- greetz, marc Don't think I'm going to miss you, any of you. I'm not. Well, maybe a little bit. Rygel - Into the Lion's Den - Wolf in Sheep's Clothing chiana 2.6.18-4-ixp4xx #1 Tue Mar 27 18:01:56 BST 2007 GNU/Linux
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <time.h> #define BUFSIZE 64*1024 /* Maximal packet content is 64k bytes */ #define MAXPARAMLEN 80 #define STATFILE "/proc/stat" #define SELFSTATFILE "/proc/self/stat" void error(char *msg); void usage(const char* program) { fprintf(stdout,"usage : %s -a address -p port\n",program); } float getsysload() { unsigned long user = 0ul, nice = 0ul, system = 0ul, idle = 0ul; char buf[BUFSIZ]; FILE *fp; char buffer[BUFSIZ]; memset(buffer,0x0,BUFSIZ); if((fp=fopen(STATFILE,"r"))<=0){ fprintf(stderr, "Problem opening %s\n", STATFILE); return EXIT_FAILURE; } fread(buffer, sizeof(char), BUFSIZ, fp); fclose(fp); if(sscanf(buffer,"%s %lu %lu %lu %lu",buf, &user, &nice, &system, &idle)){ return (float)(user+system)/(user+system+nice+idle); } else{ fprintf(stdout, "no matching strings found\n"); } } unsigned long getcurrjiffies() { FILE *fp; char buffer[BUFSIZ]; memset(buffer, 0x0, BUFSIZ); fp=popen("cat /proc/self/stat | cut -d \\ -f 22","r"); fread(buffer, sizeof(char), BUFSIZ, fp); pclose(fp); return atoi(buffer); } unsigned long scan_stat(unsigned long *user, unsigned long *kernel) { FILE *fp; char buffer[BUFSIZ]; uint32_t scanned = 0u; signed int pid = 0; char tcomm[BUFSIZ]; char state = 0x0; signed int ppid = 0; signed int pgid = 0; signed int sid = 0; signed int tty_nr = 0; signed int tty_pgrp = 0; unsigned long flags = 0ul; unsigned long min_flt = 0ul; unsigned long cmin_flt = 0ul; unsigned long maj_flt = 0ul; unsigned long cmaj_flt = 0ul; unsigned long utime = 0ul; unsigned long stime = 0ul; signed long cutime = 0l; signed long cstime = 0l; signed long priority = 0l; signed long nice = 0l; signed int num_threads = 0; unsigned long long start_time = 0ul; unsigned long vsize = 0ul; signed long rss = 0l; unsigned long rsslim = 0ul; unsigned long start_code = 0ul; unsigned long end_code = 0ul; unsigned long start_stack = 0ul; unsigned long esp = 0ul; unsigned long eip = 0ul; /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ unsigned long signalpending = 0ul; unsigned long signalblocked = 0ul; unsigned long sigign = 0ul; unsigned long sigcatch = 0ul; unsigned long wchan = 0ul; unsigned long dummy0 = 0ul; unsigned long dummy1 = 0ul; int exit_signal = 0; int task_cpu = 0; unsigned long rt_priority = 0ul; unsigned long policy = 0ul; unsigned long long delayticks = 0ull; memset(buffer,0x0,BUFSIZ); memset(tcomm,0x0,BUFSIZ); if(!(fp=fopen(SELFSTATFILE,"r"))){ fprintf(stderr,"Error opening \"%s\".\n",SELFSTATFILE); return 0; } fread(buffer, sizeof(char), BUFSIZ, fp); fclose(fp); #if 0 fprintf(stdout,"Reference:\n"); fprintf(stdout,"-------\n"); fprintf(stdout,"%s\n",buffer); fprintf(stdout,"-------\n"); #endif scanned = sscanf(buffer,"%d %s %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", &pid, tcomm, &state, &ppid, &pgid, &sid, &tty_nr, &tty_pgrp, &flags, &min_flt, &cmin_flt, &maj_flt, &cmaj_flt, &utime, &stime, &cutime, &cstime, &priority, &nice, &num_threads, &start_time, &vsize, &rss, &rsslim, &start_code, &end_code, &start_stack, &esp, &eip, /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ &signalpending, &signalblocked, &sigign, &sigcatch, &wchan, &dummy0, &dummy1, &exit_signal, &task_cpu, &rt_priority, &policy, &delayticks); #if 0 fprintf(stdout,"scanned %u items.\n",scanned); fprintf(stdout,"%d %s %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", pid, tcomm, state, ppid, pgid, sid, tty_nr, tty_pgrp, flags, min_flt, cmin_flt, maj_flt, cmaj_flt, utime, stime, cutime, cstime, priority, nice, num_threads, start_time, vsize, rss, rsslim, start_code, end_code, start_stack, esp, eip, /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ signalpending, signalblocked, sigign, sigcatch, wchan, dummy0, dummy1, exit_signal, task_cpu, rt_priority, policy, delayticks); #endif *user = utime; *kernel = stime; return utime + stime; } int main(int argc, char *argv[]) { extern int getopt(); extern int optind; extern char *optarg; int c_opt; int socket_val, bind_val, recvfromval, ctrlboardlen, rc, recvbuff; unsigned optlen, cameralen; uint16_t mc_port; char mc_addr[16]; struct ip_mreq mreq; struct sockaddr_in ctrlboard, camera; struct in_addr mcast_address; struct hostent *h; unsigned char buffer[BUFSIZE]; FILE *fp; uint32_t ucnt = 0u,i,cnt=0u; uint64_t usecs[8]; uint64_t received[8]; uint64_t treceived = 0ul; struct timeval newtime; unsigned long p_jiffies, c_jiffies; unsigned long puser, pkernel; unsigned long cuser, ckernel; unsigned long long p_start, c_start; /* Initialize the buffer */ memset(mc_addr, 0x0, 16); memset(buffer,0x0,BUFSIZE); for(i=0;i<8;i++){ usecs[i] = 0ul; received[8] = 0ul; } /* handling of command line options */ while ((c_opt = getopt(argc, argv, "a:b:p:")) != EOF) { switch (c_opt) { case 'a': strncpy(mc_addr,optarg,16); break; case 'p': mc_port = (atoi(optarg)); break; default: fprintf(stderr, "%s: Bad Option -%c\n", argv[0], c_opt); exit(EXIT_FAILURE); } } if(!mc_addr || !mc_port){ usage(argv[0]); return EXIT_FAILURE; } /* Get mcast address to listen to */ h=gethostbyname(mc_addr); if(h==NULL) { fprintf(stdout,"Unknown group %s\n",mc_addr); exit(1); } memcpy(&mcast_address, h->h_addr_list[0],h->h_length); /* Check given address is multicast */ if(!IN_MULTICAST(ntohl(mcast_address.s_addr))) { fprintf(stdout,"Given address '%s' is not multicast\n", inet_ntoa(mcast_address)); exit(1); } /* Create socket for incoming connections */ socket_val=socket(AF_INET, SOCK_DGRAM, 0); if (socket_val < 0) error("Error opening socket"); /* Set content of ctrlboard */ ctrlboardlen = sizeof(ctrlboard); bzero(&ctrlboard,ctrlboardlen); /* Fill in the UDP Receiver properties */ ctrlboard.sin_family=AF_INET; ctrlboard.sin_addr.s_addr=htonl(INADDR_ANY); ctrlboard.sin_port=htons(mc_port); /* Set socket options */ recvbuff=128*1024; if (setsockopt(socket_val,SOL_SOCKET,SO_RCVBUF,(char *) &recvbuff, sizeof(recvbuff)) < 0) error("Error setting socket options"); /* Get socket options */ optlen=sizeof(recvbuff); if (getsockopt(socket_val,SOL_SOCKET,SO_RCVBUF,(char *) &recvbuff, &optlen) < 0) error("Error getting socket options"); fprintf(stdout,"Receive buffer size: %d \n",recvbuff); /* Bind to associate port number with the socket */ bind_val = bind(socket_val,(struct sockaddr *)&ctrlboard,ctrlboardlen); if (bind_val < 0) error("Error bind"); /* join multicast group */ mreq.imr_multiaddr.s_addr=mcast_address.s_addr; mreq.imr_interface.s_addr=htonl(INADDR_ANY); rc = setsockopt(socket_val,IPPROTO_IP,IP_ADD_MEMBERSHIP, (void *) &mreq, sizeof(mreq)); if(rc<0){ fprintf(stdout,"Cannot join multicast group '%s'", inet_ntoa(mcast_address)); exit(1); } else fprintf(stdout,"Listening to mgroup %s:%d\n", inet_ntoa(mcast_address), mc_port); /* Fill in length of struct sockaddr_in camera */ cameralen = sizeof(camera); gettimeofday(&newtime,NULL); p_jiffies = scan_stat(&puser, &pkernel); p_start = getcurrjiffies(); /* Loop */ while (1) { recvfromval = recvfrom(socket_val,buffer,BUFSIZE,0,(struct sockaddr *)&camera,&cameralen); treceived += recvfromval; if (recvfromval < 0) error("Error recvfrom"); if(!(cnt&0xff)){ double cbitrate = 0.0; uint8_t ccnt = ucnt&0x7; uint8_t pcnt = ccnt?ccnt-1:0x7; uint64_t dt; c_jiffies = scan_stat(&cuser,&ckernel); c_start = getcurrjiffies(); gettimeofday(&newtime,NULL); usecs[ccnt] = (uint64_t)(newtime.tv_sec*1e6+newtime.tv_usec); received[ccnt] = treceived; dt = usecs[ccnt] - usecs[pcnt]; if(usecs[ccnt]<usecs[pcnt]){ ucnt = 0; } else{ unsigned lcnt = 0u; for(i=0;i<8;i++){ lcnt = received[i]; } if(dt){ cbitrate = (((double)lcnt*8)/((double)dt))*1e3; fprintf(stdout,"Approx bitrate is %2.2lf kbps, system load is %2.2f%%, process %2.2f%% (u %2.2f%%, s %2.2f).\n", cbitrate, getsysload()*100, (double)(c_jiffies - p_jiffies)*100/(c_start - p_start), (double)(cuser-puser)*100/(c_start - p_start), (double)(ckernel-pkernel)*100/(c_start - p_start) ); } } ucnt++; treceived = 0; p_jiffies = c_jiffies; p_start = c_start; pkernel = ckernel; puser = cuser; } cnt++; } close(socket_val); fclose(fp); } void error(char *msg) { perror(msg); exit(0); }
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <fcntl.h> #include <netdb.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/time.h> #include <time.h> #define STATFILE "/proc/stat" #define SELFSTATFILE "/proc/self/stat" void usage(const char* program) { fprintf(stdout,"Usage: %s -a address -p port -b bitrate\n",program); fprintf(stdout," bitrate in kbps.\n"); } float getsysload() { unsigned long user = 0ul, nice = 0ul, system = 0ul, idle = 0ul; char buf[BUFSIZ]; FILE *fp; char buffer[BUFSIZ]; memset(buffer,0x0,BUFSIZ); if((fp=fopen(STATFILE,"r"))<=0){ fprintf(stderr, "Problem opening %s\n", STATFILE); return EXIT_FAILURE; } fread(buffer, sizeof(char), BUFSIZ, fp); fclose(fp); if(sscanf(buffer,"%s %lu %lu %lu %lu",buf, &user, &nice, &system, &idle)){ return (float)(user+system)/(user+system+nice+idle); } else{ fprintf(stdout, "no matching strings found\n"); } } unsigned long getcurrjiffies() { FILE *fp; char buffer[BUFSIZ]; memset(buffer, 0x0, BUFSIZ); fp=popen("cat /proc/self/stat | cut -d \\ -f 22","r"); fread(buffer, sizeof(char), BUFSIZ, fp); pclose(fp); return atoi(buffer); } unsigned long scan_stat(unsigned long *user, unsigned long *kernel) { FILE *fp; char buffer[BUFSIZ]; uint32_t scanned = 0u; signed int pid = 0; char tcomm[BUFSIZ]; char state = 0x0; signed int ppid = 0; signed int pgid = 0; signed int sid = 0; signed int tty_nr = 0; signed int tty_pgrp = 0; unsigned long flags = 0ul; unsigned long min_flt = 0ul; unsigned long cmin_flt = 0ul; unsigned long maj_flt = 0ul; unsigned long cmaj_flt = 0ul; unsigned long utime = 0ul; unsigned long stime = 0ul; signed long cutime = 0l; signed long cstime = 0l; signed long priority = 0l; signed long nice = 0l; signed int num_threads = 0; unsigned long long start_time = 0ul; unsigned long vsize = 0ul; signed long rss = 0l; unsigned long rsslim = 0ul; unsigned long start_code = 0ul; unsigned long end_code = 0ul; unsigned long start_stack = 0ul; unsigned long esp = 0ul; unsigned long eip = 0ul; /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ unsigned long signalpending = 0ul; unsigned long signalblocked = 0ul; unsigned long sigign = 0ul; unsigned long sigcatch = 0ul; unsigned long wchan = 0ul; unsigned long dummy0 = 0ul; unsigned long dummy1 = 0ul; int exit_signal = 0; int task_cpu = 0; unsigned long rt_priority = 0ul; unsigned long policy = 0ul; unsigned long long delayticks = 0ull; memset(buffer,0x0,BUFSIZ); memset(tcomm,0x0,BUFSIZ); if(!(fp=fopen(SELFSTATFILE,"r"))){ fprintf(stderr,"Error opening \"%s\".\n",SELFSTATFILE); return 0; } fread(buffer, sizeof(char), BUFSIZ, fp); fclose(fp); #if 0 fprintf(stdout,"Reference:\n"); fprintf(stdout,"-------\n"); fprintf(stdout,"%s\n",buffer); fprintf(stdout,"-------\n"); #endif scanned = sscanf(buffer,"%d %s %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", &pid, tcomm, &state, &ppid, &pgid, &sid, &tty_nr, &tty_pgrp, &flags, &min_flt, &cmin_flt, &maj_flt, &cmaj_flt, &utime, &stime, &cutime, &cstime, &priority, &nice, &num_threads, &start_time, &vsize, &rss, &rsslim, &start_code, &end_code, &start_stack, &esp, &eip, /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ &signalpending, &signalblocked, &sigign, &sigcatch, &wchan, &dummy0, &dummy1, &exit_signal, &task_cpu, &rt_priority, &policy, &delayticks); #if 0 fprintf(stdout,"scanned %u items.\n",scanned); fprintf(stdout,"%d %s %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n", pid, tcomm, state, ppid, pgid, sid, tty_nr, tty_pgrp, flags, min_flt, cmin_flt, maj_flt, cmaj_flt, utime, stime, cutime, cstime, priority, nice, num_threads, start_time, vsize, rss, rsslim, start_code, end_code, start_stack, esp, eip, /* The signal information here is obsolete. * It must be decimal for Linux 2.0 compatibility. * Use /proc/#/status for real-time signals. */ signalpending, signalblocked, sigign, sigcatch, wchan, dummy0, dummy1, exit_signal, task_cpu, rt_priority, policy, delayticks); #endif *user = utime; *kernel = stime; return utime + stime; } int main(int argc, char *argv[]) { extern int getopt(); extern int optind; extern char *optarg; int c_opt; unsigned int mc_server_socket; struct sockaddr_in mc_addr_sockaddr; uint8_t TTL = 0u; uint8_t buffer[BUFSIZ]; int retval; uint16_t mc_port = 0u; char mc_addr[16]; uint32_t mc_bitrate = 0u, i, cnt = 0u, ucnt=0u; float delay = 0; unsigned long usecs[8]; unsigned long p_jiffies, c_jiffies; unsigned long puser, pkernel; unsigned long cuser, ckernel; unsigned long long p_start, c_start; struct timeval newtime; /* Init */ memset(mc_addr, 0x0, 16); for(i=0;i<8;i++){ usecs[i] = 0ul; } for(i=0;i<BUFSIZ>>2;i++){ ((uint32_t*)buffer)[i]=0xbadc0ffe; } /* handling of command line options */ while ((c_opt = getopt(argc, argv, "a:b:p:")) != EOF) { switch (c_opt) { case 'a': strncpy(mc_addr,optarg,16); break; case 'b': mc_bitrate = (atoi(optarg)); break; case 'p': mc_port = (atoi(optarg)); break; default: fprintf(stderr, "%s: Bad Option -%c\n", argv[0], c_opt); exit(EXIT_FAILURE); } } if(!mc_addr || !mc_port || !mc_bitrate){ usage(argv[0]); return EXIT_FAILURE; } /* Create a multicast socket */ mc_server_socket=socket(AF_INET, SOCK_DGRAM,0); /* Create multicast group address information */ mc_addr_sockaddr.sin_family = AF_INET; mc_addr_sockaddr.sin_addr.s_addr = inet_addr(mc_addr); mc_addr_sockaddr.sin_port = htons(mc_port); /* Set the TTL for the sends using a setsockopt() */ TTL = 1; retval = setsockopt(mc_server_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&TTL, sizeof(TTL)); if (retval < 0){ fprintf(stdout,"ERROR setsockopt() failed with %d \n", retval); return EXIT_FAILURE; } /* get estimated us delay */ delay = 1e6/((float)(mc_bitrate<<10)/(sizeof(buffer)<<3)); /* Send MC message */ fprintf(stdout,"Multicast to socket %s:%u.\n",mc_addr, mc_port); fprintf(stdout,"Requested bitrate is %u kbps.\n",mc_bitrate); fprintf(stdout,"Need %2.2f packets of %u bytes per second.\n",((float)(mc_bitrate<<10)/(sizeof(buffer)<<3)),sizeof(buffer)); fprintf(stdout,"Setting interpacket delay at %2.2f usec.\n",delay); gettimeofday(&newtime,NULL); p_jiffies = scan_stat(&puser, &pkernel); p_start = getcurrjiffies(); // usecs[ucnt++] = newtime.tv_sec*1e6+newtime.tv_usec; while(1){ /* Send buffer as a datagram to the multicast group */ sendto(mc_server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&mc_addr_sockaddr, sizeof(mc_addr_sockaddr)); usleep(delay); if(!(cnt&0xff)){ double cbitrate = 0.0; uint8_t ccnt = ucnt&0x7; uint8_t pcnt = ccnt?ccnt-1:0x7; unsigned long dt; c_jiffies = scan_stat(&cuser,&ckernel); c_start = getcurrjiffies(); gettimeofday(&newtime,NULL); usecs[ccnt] = newtime.tv_sec*1e6+newtime.tv_usec; dt = usecs[ccnt] - usecs[pcnt]; if(usecs[ccnt]<usecs[pcnt]){ ucnt = 0; } else{ cbitrate = ((((double)sizeof(buffer)*8)*0xff)/((float)dt))*1e3; fprintf(stdout,"Approx bitrate is %2.2lf kbps, system load is %2.2f%%, process %2.2f%% (u %2.2f%%, s %2.2f).\n", cbitrate, getsysload()*100, (double)(c_jiffies - p_jiffies)*100/(c_start - p_start), (double)(cuser-puser)*100/(c_start - p_start), (double)(ckernel-pkernel)*100/(c_start - p_start) ); if(((cbitrate+256)<mc_bitrate)){ delay -= 500; fprintf(stdout,"Interpacket delay adjusted to %2.2f usec\n",delay); } else if ((cbitrate-256)>mc_bitrate){ delay += 500; fprintf(stdout,"Interpacket delay adjusted to %2.2f usec\n",delay); } if(delay<0){ fprintf(stderr,"Cannot send data out fast enough.\n"); mc_bitrate -= 1024; delay = 0; fprintf(stdout,"Limiting data to %u kbps.\n",mc_bitrate); } ucnt++; } p_jiffies = c_jiffies; p_start = c_start; pkernel = ckernel; puser = cuser; } cnt++; } /* Close and clean-up */ close(mc_server_socket); return EXIT_SUCCESS; }
signature.asc
Description: Digital signature
_______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev