Sunday 31 January 2016

Random Numbers from Salt (Radiation)

I bought a cheap Geiger Counter Kit from China to generate some random numbers. I wired it up to an Arduino Uno and wrote a basic sketch (lots plagiarised, but I have references back to their sources in the code) that generates random numbers from radioactive decay events. This is something that should, by its very nature be totally chaotic and not be predictable using classical or even quantum physics.

The basic theory is to record the time of 4 consecutive detected decay events. The time interval between the first two events will be greater than the time interval between the second two events 50% of the time on average. Allocate a 1 bit if this occurs and allocate a 0 bit if the opposite occurs [first interval is less than the second interval].

Wiring

Arduino 5V <-> middle pin of the three on the left side of the detector (labelled 5V).
Arduino Ground <-> top  pin of the three on the left side of the detector (labelled GND).
Arduino Pin 2 <-> bottom pin of the three on the left side of the detector (labelled VIN)
I also removed jumper J1 on the detector  to stop it clicking. The jumper actually still on the board but only on one pin, instead of bridging the both pins as it would by default.

One nice thing about this setup is that the Arduino is powering up the Geiger Counter Kit (both together are using about 0.04A @ 5.00 V =0.2 Watts - measured by a "USB Charger Doctor").

Radiation sources

The Geiger Müller tube used is sensitive to Beta and Gamma radiation (M4011), so I did a quick search for sources of radiation that I would feel comfortable owning, or ordering online and having delivered (for some odd reason I can picture the postman freaking out carrying a package with a big yellow radiation warning sticker on it).

Bananas have so little Potassium-40 in them, to be nearly invisible from background radiation (which is very comforting if you like to eat Bananas) - 0.098 μSv. And since the human body strictly controls the percentage of Potassium at a constant level, you should not let this information distract you from eating bananas their goodness far out ways any negative.

Opening an old fire alarm for its Americium-241 ionizing source would be useless since it is an alpha emitter [and low energy gamma rays of 60 keV]. (alpha can't get into my detector and most gamma pass right through my detector unnoticed) [An average smoke detector for domestic use contains about 0.29 micrograms of Am-241 (in the form of americium dioxide), so its activity is around 37,000 becquerel (or about 1 µCurie)]. But in terms of danger factor, versus happiness - I'll give it a very wide berth.

I could scour antique shops looking for old radioactive consumer products like Fiesta Ware or Vaseline/Uranium Glass but I do not feel the need to add radioactive items into my living environment.

You can call me crazy but I do not really feel comfortable with most radiation sources, so for my test I decided to use background radiation and some easily accessible Potassium-40 which should be around about 10x background levels.

I only used two sources for my radiation. One thing to keep in mind is that my Geiger Müller tube itself is slightly radioactive, just like everything, so I get about 0.2 pulses/second from the tube.

background radiation (where I live)
~ one decay event every 3 seconds
~18 counts per minute (CPM) [0.122 μSievert]
~0.29 counts per second (CPS)
~0.0725 bits/second
~0.009 bytes/second
~ 0.54 bytes/minute
~783 bytes/day

LO-SALT [66% Potassium Chloride] emits Beta particles from K-40
~ three decay events every one second
~161 counts per minute (CPM) [~1.06 μSievert]
~2.68 counts per second (CPS)
~0.67 bits/second
~0.084 bytes/second
~ 5.05 bytes/minute 
~7260 bytes/day
 




I could always check into using Caesium-137 or a Strontium-90 source at some later date. But in all honesty I think that I'll go in a different direction for generating random numbers. The sources I would feel comfortable using are not all that cheap as well.

Here is the sketch that I used to measure the CPM of the background and LO-SALT and print the result every 60 seconds:
// http://www.rhelectronics.net/store/radiation-detector-geiger-counter-diy-kit-second-edition.html
// https://github.com/revspace/geiger
// http://forum.arduino.cc/index.php?topic=336041.25;wap2
#define LOG_PERIOD 60000 //Logging period in milliseconds, recommended value 15000-60000.
#define MAX_PERIOD 60000 //Maximum logging period without modifying this sketch

unsigned long counts;     //variable for GM Tube events
unsigned long cpm;        //variable for CPM
unsigned int multiplier;  //variable for calculation CPM in this sketch
unsigned long previousMillis;  //variable for time measurement
float uSv;            // the measured microSiverts
float ratio = 151.5; // 151 CPM = 1uSv/h for M4011 GM Tube

void tube_impulse(){               //procedure for capturing events from Geiger Kit
  counts++;
}

void setup(){                                               //setup procedure
  counts = 0;
  cpm = 0;
  multiplier = MAX_PERIOD / LOG_PERIOD;  //calculating multiplier, depend on your log period
  Serial.begin(115200);                                    // start serial monitor
 // uncommennt if you have time-out problem to connect with Radiation Logger
 //  delay(2000);
 //  Serial.write('0'); // sending zero to avoid connection time out with radiation logger
 //  delay(2000);
 //  Serial.write('0'); // sending zero to avoid connection time out with radiation logger
  pinMode(2, INPUT);    // set pin INT0 input for capturing GM Tube events
  digitalWrite(2, LOW); // turn on internal pullup resistors, solder C-INT on the PCB
  attachInterrupt(0, tube_impulse, FALLING);  //define external interrupts
}

 

void loop(){                                               //main cycle
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > LOG_PERIOD){
    previousMillis = currentMillis;
    cpm = counts * multiplier;    
    Serial.print(cpm);
    Serial.print(' CPM ');
    uSv = cpm / ratio ;
    Serial.print(uSv); 
    Serial.println(' uSv ');
    counts = 0;
  }
}


And, here is the sketch that I ran on my Arduino to generate the random numbers:

// This code generates random numbers based on nuclear decay events, 
// In my mind they would be the highest quality of random numbers.
// The only downside is that it is very very very very very slow. 
//
// Using only background radiation of about 18CPM it would take
// about 30 hours to generate 1k of random goodness.
// Using  low-sodium kitchen salt, you can get about 10x background radiation.
// Using LoSalt (66% potassium Chloride) 161CPM it would take about 
// 202 minutes to generate 1k of random goodness.
// Using some crazy lethal radiation source of 170,000CPM (60*1000000/350)
// (maximum with my GM tube recovery time of ~350uS) it would take about 
// 200 minutes to generate 1MiB of random numbers
//
// This is one of the reasons that I would not use a GM tube as my final solution 
// to generate high quality truly random numbers, but it is interesting to test.
//
// Using background where I am is about 18 CPM I can generate about 0.53 bytes/minute
// Using Lo-Salt (66% Potassium Chloride) 161 CPM I can generate about 5 bytes/minute
//
// 2016-01-31
// Remove all elegance and make it dumb, just bit bang pins until they change state.
// For optimal timing resolution sometimes doing things as basic as 
// possible is the most efficient technique.
//
// 2016-01-30
// This is a rewrite to gather 4 decays and generate one bit of randomness without
// using interrupts also we will use the rising edge instead of the falling edge as
// the trigger for a new decay This is so that code is running while the GM tube 
// is recovering from the previous decay event
//
// 2016-01-13
// some critical code from 
// https://www.fourmilab.ch/hotbits/source/hotbits-c3.html
// and some code is from 
// https://github.com/revspace/geiger
// and some useful info from
// http://tinkerman.eldiariblau.net/geiger-counter/
//
// The Geiger Counter is connected to pin 2 
// each pulse every time a decay is detected about ~350 microseconds in duration 
// I measured that with the following very basic code:
// unsigned long array[101];
// int counter=0;
//
// void setup(){ 
// Serial.begin(115200); 
// pinMode(2, INPUT); 
//}
//
//void loop(){ 
// array[counter++]=pulseIn(2,LOW);
// if(counter > 100)
//   for(;--counter;counter>1)
//     Serial.println(array[counter]); 
//}
// For my Geiger Counter Kit it's default is low, it pulses high for ~350uS 
// on a decay event and returns to low

const int GMpin = 2;
const int LEDpin = 13;
int LEDstate=HIGH;
unsigned long triggeredTime[4]; 
unsigned char bits;
unsigned long duration1, duration2;
int flipper = 0; // flip bit that gets toggled every time a new bit is generated. 
int shift = 0; // track how many bits have we shifted


void setup() {
 Serial.begin(115200);
 pinMode(GMpin, INPUT);
 digitalWrite(LEDpin,LEDstate); 
 pinMode(LEDpin, OUTPUT);
 digitalWrite(GMpin,LOW); // turn on internal pullup resistor
}


void loop() {
// 4 highs and 4 lows is one bit, or 4 independent decay events
// 0L-(unknown)->1H-(~350uS)->2L-(unknown)->3H-(~350uS)->4L
// 4L-(unknown)->5H-(~350uS)->6L-(unknown)-7H->(~350uS)->0L
//
// Wait 0L->1H
 while (digitalRead(GMpin) == LOW) {}; // wait here while the GM is low.
 triggeredTime[0] = micros(); // first decay has occurred
 digitalWrite(LEDpin,LEDstate); // toggle the LED once for each new bit
 LEDstate=!LEDstate;
// Wait 1H->2L (~350uS)
 while (digitalRead(GMpin) == HIGH) {}; // wait here while the GM is high ~350uS
// Wait 2L->3H
 while (digitalRead(GMpin) == LOW) {}; // wait here while the GM is low.
 triggeredTime[1] = micros(); // second decay has occurred
// Wait 3H->4L (~350uS)
 while (digitalRead(GMpin) == HIGH) {}; // wait here while the GM is high ~350uS
// Wait 4L->5H
 while (digitalRead(GMpin) == LOW) {}; // wait here while the GM is low.
 triggeredTime[2] = micros(); // third decay has occurred
 digitalWrite(LEDpin,LEDstate); // toggle the LED once for each new bit
 LEDstate=!LEDstate;
// Wait 5H->6L (~350uS)
 while (digitalRead(GMpin) == HIGH) {}; // wait here while the GM is high ~350uS
// Wait 6L->7H
 while (digitalRead(GMpin) == LOW) {}; // wait here while the GM is low.
 triggeredTime[3] = micros(); // fourth decay has occurred
 
 duration1=triggeredTime[1]-triggeredTime[0]; // first two decay events 3H-1H
 duration2=triggeredTime[3]-triggeredTime[2]; // second two decay events 7H-5H
 if (duration1 != duration2) {
          /* There remains the possibility of a very slight bias due
             to long-term effects such as ionisation of a Geiger tube,
             poisoning of a silicon detector, or (absurdly small for
             any practical source) decrease in radioactivity of the source
             over time.  To mitigate this, we invert the sense of the
             magnitude test between the first and second samples for
             alternate samples.  This pushes the effect of any long-term
             bias to a much higher order effect. */ 
   flipper ^= 1;
   bits = (bits << 1) | (flipper ^ (duration1 > duration2));
   shift++;
   if(shift>7) { // we have bits 0-7 collected, time to display the two nibbles.
     if((bits&0xF0) == 0x00) // is the first nibble zero
       Serial.print("0");    // if it is then print the leading zero.
     Serial.print(bits, HEX); // this command does not print out leading zeroes
     shift=0; // time to start collecting a new byte.
    } 
  }

// I could just assume that my code above will take longer than ~350uS 
// (5600 clock cycles @ 16MHz] which would be a bad assumption. So I added the 
// following line just to be safe. The worse case is that I miss one decay event.
// Wait 7H->0L (~350uS)
 while (digitalRead(GMpin) == HIGH) {}; // wait here while the GM is high ~350uS
}

The above code sends hex digits one byte at a time to the serial port. To capture the random numbers and store them to file I used the following commands on Linux "screen -L /dev/ttyACM0 115200" [^A D - to exit the screen session and return to the console] this creates a logfile called screenlog.0 which captures all data coming to the USB serial port from the Arduino. Or you could use "(stty -F /dev/ttyACM0 raw ispeed 115200 ; cat > random.txt) < /dev/ttyACM0"

And to convert them from ASCII into binary I used the following UNIX command:
$ cat  screenlog.0 | xxd -r -p - random.bin

And this binary file can be tested with rngtest if the filesize is at least 2500 bytes (20000 bits). Unfortunately since the randomness generation rate is low, it would take multiple centuries to generate the Gigabytes of data required for one run of the full dieharder randomness test suite, using a single Geiger Müller tube even with the most radioactive source possible. So as much as it was fun playing with a Geiger counter, for generating random numbers, I feel that it is a dead end, at least for me. The quality of the randomness it fantastic but the generation rate is far too low, at least for my needs.

Sunday 29 November 2015

Part Two: Airspy R2 - Questions and Answers

Question   1: There are three multiplexed ADC channels in the Airspy, is there a simple way to access the other two if I wanted to implement a custom DDC firmware? 
Answer     1: .By default channel 0 is used for the R820T2, but channel 1 and channel 2 are unconnected. You could hack the firmware source code and modify this line "#define DEFAULT_ADCHS_CHAN (0)" in "firmware/airspy_m4/airspy_m4.c" to use channel 1 or channel 2 instead of channel 0 which is connected to the output of the R820T2 tuner chip.
Of course the R820T2 would still be powered on so you should disable it, since you are not using it (use disable_r820t_power() anywhere where enable_r820t_power() is called) because it may add unwanted noise. Of course disabling the R820T2 chip, also means that you should delete/disable any calls to set registers in it, since you are not be using it. You should also delete/disable the frequency tuning from the firmware since the tuner is not used. And by the time you have done that it might be easier just to write your own custom firmware.

Extra info  1: Since the spyverter is now available it might be easier just to use it unless you actually need an ADC, that in theory could run at 80MSPS. The problem is that the USB bus will limit the data transfer to about 20MSPS. And there is not enough RAM in the LPC4370 to buffer more than about 2x16KiB (double buffering) or 32KiB of data, and there is not enough processing power within the CPU to reduce this data. So unless 32KiB of data sampled at 80MSPS is enough for your function this is probably a dead end for your idea. If you are still going to use the two ADC ports the good news is that there is ESD protection in the R2 board, the R0 board had no ESD protection on the ADC inputs.


Monday 2 March 2015

How to use Kal software to workout the PPM frequency offset of a RTL-SDR

The basic idea behind the Kalibrate software is that a GSM mobile phone base station has an expensive very high precision atomic clock (0.01ppb), where as a RTL-SDR stick has a cheap low  precision 28.8MHz quartz crystal (+/-100ppm). This cheap low  precision oscillator is used to derive all frequencies when you tune the RTL-SDR, so the bigger the errors the more you are offset from the correct frequency. There are two pieces of good news the offset is linear and once the cheap crystal has warmed up it generally does not drift very much. Because the error is linear across the whole frequency range, only one correction value is required.

When you buy a 28.8MHz quartz crystal in a can, they are generally not 28,800,000Hz. There are two problems that need to be compensated for by the PPM offset in SDR receiver software. The first is manufacturing tolerance, generally about 100 PPM (0.01%) is the range to keep costs down, so the frequency of a new quartz crystal could be anywhere between 28,797,120Hz and 28,802,880Hz at 20 degrees Celsius. The second problem is that the frequency will change slightly as the device warms up. But the good news is once the device has warmed up it will not drift much, unless the ambient room temperature varies.

So basically you scan the local area for active GSM base station channels with a large amount of power (good signal strength, which will probably be from the base station that is physically closest to your current location). Then kal uses this channels GSM frequency correction bursts to workout the PPM (part per million) offset of the RTL-SDR that you are currently calibrating.


Download, compile and install the kal software

$ sudo apt-get install libtool autoconf automake libfftw3-dev
$ git clone https://github.com/steve-m/kalibrate-rtl
$ cd kalibrate-rtl
$ ./bootstrap && CXXFLAGS='-W -Wall -O3'
$ ./configure 
$ make 
$ sudo make install


Use the kal software to scan GSM base stations for channels with high power

My RTL-SDR only goes from 24MHz to 1750MHz, so I can not use the DCS or PCS GSM system, even if they were active in my area. I know that EGSM is active where I am, but I'll test all the frequencies to time and show how long a scans takes when no GSM is present, as well as how long it takes when GSM base stations are present (about 2-10 minutes). This will also provide the warm up time of about 10 minutes for my RTL-SDR to reach its steady state operating temperature. Some of the GSM down link frequencies are used to send the frequency correction bursts, to calibrate mobile phone handsets, so that the phones know the correction offset to use when TX'ing on the up link frequencies. This allows mobile phone makers to use cheaper hardware in their handsets, and if you are making a few billion of them small savings quickly add up to more profit..
  • GSM850  UPLINK:   824.2-  849.2MHz DOWNLINK:   869.2-  894.2MHz
  • GSM-R     UPLINK:   876.0-  915.0MHz DOWNLINK:   921.0-  960.0MHz
  • GSM900  UPLINK:   890.0-  915.0MHz DOWNLINK:   935.0-  960.0MHz
  • EGSM      UPLINK:   880.0-  915.0MHz DOWNLINK:   925.0-  960.0MHz
  • DCS         UPLINK: 1710.2-1784.8MHz DOWNLINK: 1805.2-1879.8MHz
  • PCS         UPLINK: 1850.2-1909.8MHz DOWNLINK: 1930.2-1989.8MHz
(Source of above info https://en.wikipedia.org/wiki/GSM_frequency_bands#Bands)

(confirm that the RTL-SDR is actually plugged into the Linux machine)
$ lsusb | grep -i RTL
Bus 004 Device 015: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T

(print the help for the kal software to see what arguments should be used)
$ kal
error: must enter channel or frequency
kalibrate v0.4.1-rtl, Copyright (c) 2010, Joshua Lackey
modified for use with rtl-sdr devices, Copyright (c) 2012, Steve Markgraf
Usage:
        GSM Base Station Scan:
                kal <-s band indicator> [options]

        Clock Offset Calculation:
                kal <-f frequency | -c channel> [options]

Where options are:
        -s      band to scan (GSM850, GSM-R, GSM900, EGSM, DCS, PCS)
        -f      frequency of nearby GSM base station
        -c      channel of nearby GSM base station
        -b      band indicator (GSM850, GSM-R, GSM900, EGSM, DCS, PCS)
        -g      gain in dB
        -d      rtl-sdr device index
        -e      initial frequency error in ppm
        -v      verbose
        -D      enable debug messages
        -h      help
$


$ date ; kal -s GSM850 ; date
Mon Mar  2 16:05:26 CET 2015
Found 1 device(s):
  0:  Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for GSM-850 base stations.
GSM-850:
Mon Mar  2 16:08:44 CET 2015
$ date ; kal -s GSM-R ; date
Mon Mar  2 16:16:37 CET 2015
Found 1 device(s):
  0:  Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for GSM-R-900 base stations.
GSM-R-900:
Mon Mar  2 16:17:09 CET 2015
$ date ; kal -s GSM900 ; date
Mon Mar  2 16:19:42 CET2015
Found 1 device(s):
  0:  Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for GSM-900 base stations.
GSM-900:
        chan: 9 (936.8MHz + 22.294kHz)  power: 52744.70
        chan: 11 (937.2MHz + 22.198kHz) power: 148897.40
        chan: 48 (944.6MHz + 21.298kHz) power: 64839.80
        chan: 50 (945.0MHz + 21.360kHz) power: 76421.47
        chan: 66 (948.2MHz + 21.020kHz) power: 100342.53
        chan: 68 (948.6MHz + 21.109kHz) power: 148650.05
        chan: 74 (949.8MHz + 21.369kHz) power: 57399.97
Mon Mar  2 16:23:30 CET 2015
$ date ; kal -s EGSM ; date
Mon Mar  2 16:24:36 CET 2015
Found 1 device(s):
  0:  Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Scanning for E-GSM-900 base stations.
E-GSM-900:
        chan: 9 (936.8MHz + 22.059kHz)  power: 55782.16
        chan: 11 (937.2MHz + 22.136kHz) power: 141612.90
        chan: 48 (944.6MHz + 21.194kHz) power: 60347.62
        chan: 49 (944.8MHz + 20.859kHz) power: 52131.68
        chan: 50 (945.0MHz + 21.268kHz) power: 79892.10
        chan: 66 (948.2MHz + 21.026kHz) power: 95478.05
        chan: 68 (948.6MHz + 21.074kHz) power: 142679.30
        chan: 74 (949.8MHz + 21.314kHz) power: 73531.29
        chan: 985 (927.2MHz + 23.002kHz)        power: 79791.55
        chan: 988 (927.8MHz + 22.555kHz)        power: 64283.53
        chan: 992 (928.6MHz + 21.866kHz)        power: 57287.97
        chan: 1000 (930.2MHz + 22.159kHz)       power: 192336.94
Mon Mar  2 16:29:38 CET 2015

$

Use the kal software to calculate the PPM clock offset of a RTL-SDR.

So  now that I have at least one channel number, with a high broadcast power in my region,  I can calculate the PPM offset with the kal software (best if the RTL-SDR has had a chance to warm up, the cheap 28.8MHz quartz crystal probably drifts most with temperature).


$ date ; kal -c 1000 ; date
Mon Mar  2 16:37:01 CET 2015
Found 1 device(s):
  0:  Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Exact sample rate is: 270833.002142 Hz
kal: Calculating clock frequency offset.
Using E-GSM-900 channel 1000 (930.2MHz)
average         [min, max]      (range, stddev)
+ 22.137kHz             [22112, 22160]  (49, 13.404841)
overruns: 0
not found: 0
average absolute error: -23.798 ppm
Mon Mar  2 16:37:23 CET 2015
$

Since there where no overruns and the signal was found every time I know that this is a good result, that I can confidently use this value with this particular RTL-SDR hardware in GRC or SDRSharp. I would round this number and use a PPM offset of -24 (0.0024%), since none of the software supports PPB corrections (yet). Even if there were 1 to 2 overruns or 1 to 5 not-found the PPM value would still probably be valid, it just meant that there was interference during the test or the signal strength of the channel used was not high enough, maybe try the test again using a different channel, that has more power (or less interference).


The Kalibrate software actually uses the GSM signals own inbuilt frequency correction bursts, that are used by mobile phone handsets (which also have cheap quartz crystals inside them) to calculate their ppm frequency correction. The original open source software was written for the Ettus Research USRP hardware and was ported work with the RTL-SDR.

Tuesday 25 November 2014

Banana Pi USB 2.0 'Gigabit' Ethernet Adapter throughput test

Banana Pi USB 2.0 'Gigabit' Ethernet Adapter throughput test

I bought a cheap USB 2.0 to Gigabit Ethernet Adapter (Maximum Data Transfer Rate 480 Mbps according to the website), mostly because I wanted to see how it performed on a Raspberry Pi, so now I'm running the same tests on my new board the Banana Pi. It can never reach 480Mbps, but it will be interesting to see how much throughput it can actually achieve.

As usual, I have censored any identifying information about my local network or personal hardware.

Hardware Configuration:

Banana Pi
RAM 1024MB
no overclocking
Inbuilt 10/100/1000 NIC is not connected.
Top USB port has USB 2.0 to Gigabit Ethernet Adapter plugged in and plugged.into router
Bottom USB port is empty





      
+---+  +------+         +------+           +----------------+
|BPi|->|USB2.0|->1Gbps->|router|->200Mbps->|Remote webserver|
+---+  +------+ Ethernet+------+ Internet  +----------------+
      
480Mibps             |
                         1Gbps Ethernet
                            |
                            v
                     +-------------+
                     |LAN webserver|
                     +-------------+


Software Configuration: 

I had to add in an extra three lines for this new USB eth1 NIC to get it working on the Banana Pi, the lines in bold below.

root@bananapi ~ # cat /etc/network/interfaces
allow-hotplug eth1
auto lo
iface lo inet loopback
auto eth0
 
iface eth0 inet dhcp
auto eth1 
iface eth1 inet dhcp

root@bananapi ~ #

root@bananapi ~ # lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 002: ID 0424:7500 Standard Microsystems Corp. LAN7500 Ethernet 10/100/1000 Adapter
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
root@bananapi ~ # lsusb -t
/:  Bus 05.Port 1: Dev 1, Class=root_hub, Driver=sw-ohci/1p, 12M
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=sw-ehci/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Vendor Specific Class, Driver=smsc75xx, 480M

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=sw-ohci/1p, 12M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=sw-ehci/1p, 480M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=sw_hcd_host0/1p, 480M

root@bananapi ~ # ethtool eth1
Settings for eth1:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Half 1000baseT/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  10baseT/Half 10baseT/Full
                                             100baseT/Half 100baseT/Full
                                             1000baseT/Half 1000baseT/Full
        Link partner advertised pause frame use: Symmetric Receive-only
        Link partner advertised auto-negotiation: Yes
        Speed: 1000Mb/s
        Duplex: Full

        Port: MII
        PHYAD: 1
        Transceiver: internal
        Auto-negotiation: on
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes
root@bananapi ~ #

root@bananapi ~ # netstat -i
Kernel Interface table
Iface   MTU Met   RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0       1500 0         0      0      0 0             4      0      0      0 BMU
eth1       1500 0       457      0      0 0           485      0      0      0 BMRU
lo        16436 0         1      0      0 0             1      0      0      0 LRU
root@bananapi ~ #

root@bananapi ~ # ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 80:3f:5d:**:**:**
          inet addr:
*.*.*.*  Bcast:*.*.*.*  Mask:*.*.*.* 
          inet6 addr: fe80::823f:5dff:fe08:69ad/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:470 errors:0 dropped:0 overruns:0 frame:0
          TX packets:502 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:37207 (36.3 KiB)  TX bytes:72520 (70.8 KiB)

root@bananapi ~ #

Internet Test (via a 200Mbit/sec broadband connection)


Download a single 100MiB file to the Pi through the USB 2.0 Gigabit Ethernet Adapter and send the downloaded data to /dev/null.

root@bananapi ~ # time wget http://qrng.physik.hu-berlin.de/files/speedtest-100MB.bin -O /dev/null
--2010-01-01 00:17:55--  http://qrng.physik.hu-berlin.de/files/speedtest-100MB.bin
Resolving qrng.physik.hu-berlin.de (qrng.physik.hu-berlin.de)... 141.20.41.134
Connecting to qrng.physik.hu-berlin.de (qrng.physik.hu-berlin.de)|141.20.41.134|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: ‘/dev/null’

/dev/null                                           100%[=====================================================================================================================>] 100.00M  11.4MB/s   in 16s

2010-01-01 00:18:11 (6.21 MB/s) - ‘/dev/null’ saved [104857600/104857600]

wget http://qrng.physik.hu-berlin.de/files/speedtest-100MB.bin -O /dev/null  0.25s user 2.22s system 14% cpu 16.559 total
root@bananapi ~ #

LAN Test

Download a single 100MiB file to the Pi through USB 2.0 Gigabit Ethernet Adapter and send the downloaded data to /dev/null. The data source is on the Local network from a machine with a 1 Gbit/sec NIC patched directly into the router with the data being read from a RAM disk to maximise read speed.
root@webserver:~# apt-get install nginx nginx-common nginx-full
root@webserver:~# /usr/sbin/nginx &
root@webserver:~# mkdir /usr/share/nginx/www/ramdisk
root@webserver:~# chmod 777 /usr/share/nginx/www/ramdisk
root@webserver:~# free -m
root@webserver:~# mount -t tmpfs -o size=256M tmpfs /usr/share/nginx/www/ramdisk
root@webserver:~# cp speedtest-100MB.bin /usr/share/nginx/www/ramdisk


root@bananapi ~ # time wget http://*.*.*.*/ramdisk/speedtest-100MB.bin -O /dev/null
--2014-11-20 21:10:47--  http://
*.*.*.*/ramdisk/speedtest-100MB.bin
Connecting to
*.*.*.*:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: ‘/dev/null’

/dev/null                                           100%[=====================================================================================================================>] 100.00M  39.5MB/s   in 2.5s

2014-11-20 21:10:50 (39.5 MB/s) - ‘/dev/null’ saved [104857600/104857600]

wget http://
*.*.*.*/ramdisk/speedtest-100MB.bin -O /dev/null  0.24s user 1.60s system 71% cpu 2.572 total
root@bananapi ~ #


Results
Peak Internet transfer rate 10.87MiB/sec (91.2Mbps) - about 13 hops away
Average Internet throughput 6.04MiB/sec - about 13 hops away.

Because this server is so many hops away it's throughput varies wildly with time of day and is effected by so  many uncontrolled fluctuations on every hop in between. This result is more an example of a typical Internet based throughput than a maximum throughput.




Peak LAN download transfer rate 38.88 MiB/sec (326.15Mbps) - for 1000Mbps (even limited to USB 2.0 480Mbps) this is a very good throughput.
Average LAN download throughput 38.88 MiB/sec - for 1000Mbps (even limited to USB 2.0 480Mbps) this is a very good throughput.

I'm very pleased with the USB 2.0 Gigabit Ethernet Adapter result for the Banana Pi. I was expecting a result somewhere between 20 MiB/sec and 40 MiB/sec. 


I enabled jumbo frames ("sudo ifconfig eth1 mtu 9000") on the webserver and on the Banana Pi to see if I could get a better result, but I couldn't get it to work. I'm not quite sure why, yet but I'm still looking into it.

Additional testing

I decided to try the test in reverse. Install a webserver on the Banana P, and make a 128MiB ramdisk to download a file from the Banana Pi through USB 2.0, through the USB 2.0 Gigabit Ethernet Adapter down to the midrange PC with a Gigabit NIC, and then throw the data away.
root@bananapi ~ # apt-get install nginx
root@bananapi ~ # mkdir /var/www/html/ramdisk
root@bananapi ~ #  chmod 777 /var/www/html/ramdiskroot@bananapi ~ #  free -m 
root@bananapi ~ #  mount -t tmpfs -o size=128M tmpfs /var/www/html/ramdisk
root@bananapi ~ #  cp speedtest-100MB.bin /var/www/html/ramdisk

midrangepc $ time wget http://*.*.*.*/ramdisk/speedtest-100MB.bin -O /dev/null
--2014-11-20 22:39:33--  http://
*.*.*.*/ramdisk/speedtest-100MB.bin
Connecting to
*.*.*.*:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: `/dev/null'

100%[=================================================================================================================================================================>] 104,857,600 19.8MB/s   in 5.1s

2014-11-20 22:39:38 (19.7 MB/s) - `/dev/null' saved [104857600/104857600]


real    0m5.075s
user    0m0.268s
sys     0m1.592s
midrangepc $





Average LAN upload throughput 19.6 MiB/sec (156.8Mbps)

I'm not quite sure why upload is always less than download throughput rates, it is something that I'll have to think about for a while.

For two final tests I decided to unplug the USB 2.0 Gigabit ethernet adapter and use the Banana Pi's actual builtin Gigabit NIC and just get the average throughput in each direction (using a ramdisk on each machine to upload the file from as fast as possible).

Midrange server as the webserver: 101 MB/s (Banana Pi as the client, running wget) [808Mbps 96.3MiB/sec]
Banana Pi as the webserver: 71.5 MB/s (Midrange PC server as the client, running wget) [572Mbps 68.2MiB/sec]



Thursday 20 November 2014

Comparison of Raspberry Pi vs Beaglebone Black vs Banana Pi

Update (2015-2): I'll update the below when I get more info on the new BCM2836 chip used in the Raspberry Pi Generation 2 model B. It CPU performance should jump up by about six, the RAM has doubled, but the GPU is the same as is everything else. RAM performance will be the same, no clocking improvement, just size. The quad core CPU (ARMv7) does now have NEON support so SIMD, should improve data processing ability. But the real bottleneck to the RPi is getting data into and out of the CPU from the real world, it is like a giant head sitting on a straw.


CPU

From each of the /proc/cpuinfo files shown below, in theory if an application is single threaded the Banana Pi should win, and if it is multithreaded the Banana Pi should still win. I have not run any direct benchmark, just looking at the BogoMIPS and the Features supported by each ARM chip.

Raspberry Pi (Model A,B,B+,A+ all have the same ARM1176JZF-S)
------------
Processor       : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS        : 697.95
Features        : swp half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xb76
CPU revision    : 7

Hardware        : BCM2708
Revision        : 000f

BeagleBone Black
----------------
processor    : 0
model name    : ARMv7 Processor rev 2 (v7l)
BogoMIPS    : 990.68
Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls
CPU implementer    : 0x41
CPU architecture: 7
CPU variant    : 0x3
CPU part    : 0xc08
CPU revision    : 2

Hardware    : Generic AM33XX (Flattened Device Tree)
Revision    : 0000
Serial        : 0000000000000000


Banana Pi (The Banana Pro has the same Allwinner A20)
---------
Processor       : ARMv7 Processor rev 4 (v7l)
processor       : 0
BogoMIPS        : 2004.17

processor       : 1
BogoMIPS        : 2011.05

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 4

Hardware        : sun7i
Revision        : 0000



Video/GPU


Raspberry Pi:  Broadcom VideoCore IV (Graphics and compute) 24 GFLOPS
Beaglebone Black: PowerVR SGX530 (200 MHz) (Graphics, video encoding, decoding only) 1.6 GFLOPS
 Banana Pi: ARM Mali400MP2 dual GPU core (Grahpics, video encoding, decoding only) 6.3 GFLOPS 


RAM


Raspberry Pi ( A, A+, B rev 1): 256MiB DDR
Raspberry Pi (B rev 2, B+): 512MiB DDR
BeagleBone Black: 512MiB DDR3L
Banana Pi: 1024MiB DDR3

[DDR3 is 1.35 volt and DDR3L 1.25 volt (lower power = less heat = longer life)]

 

USB


Raspberry Pi A: 1 x Standard A host port (direct).
Raspberry Pi B: 2 x Standard A host port (via hub with Ethernet).
Raspberry Pi A+: 1 x Standard A host port (direct).
Raspberry Pi B+: 4 x Standard A host port (via hub with Ethernet).
Beaglebone Black: 1 x Standard A host port (direct) 1x mini B device port (direct)
Banana Pi: 2 x Standard A host port (direct) 1x mini AB OTG port (direct)
 

Ethernet

Raspberry Pi (B, B+): 10/100Mbps (shared USB)
Beaglebone Black: 10/100Mbps
Banana Pi: 10/100/1000Mbps

Storage


SD/microSD

Raspberry Pi A,B: SD card
Raspberry Pi A+, B+:  microSD card
Beaglebone Black:  microSD card
Banana Pi:  SD card

8-bit eMMC 

Raspberry Pi: None
Beaglebone Black ((Rev B): 2 GB Ångström pre-installed
Beaglebone Black ((Rev C): 4 GB Debian pre-installed
Banana Pi: None

SATA

Raspberry Pi: None
Beaglebone Black: None
Banana Pi: SATA 2.0

Me personally I hate devices with inbuilt flash, 3000-5000 writes per block and the device ready for the bin.


GPIO/Low-level peripherals

Raspberry Pi A, B rev 1: UART, SPI, 2x I²C,MIPI CSI-2, (not yet enabled DSI, CEC)
                                       8-17GPIO pins
Raspberry Pi B rev 2: UART, SPI, 2x I²C,MIPI CSI-2, (not yet enabled DSI, CEC)
                                  12-21GPIO pins

Raspberry Pi A+, B+: UART, SPI, 2x I²C,MIPI CSI-2, (not yet enabled DSI, CEC)
                                   EEPROM ID feature for auto-configuration with add-on "HAT" boards
                                   21-30GPIO pins

Beaglebone Black: 4xUART(1xTX only), 8x PWM, LCD, GPMC, MMC1, 2x SPI, 2x I²C, 7xADC(1.8v), 2x CAN bus, 4 Timers, 25xPRU
                                  65 GPIO pins
Banana Pi:  UART, SPI, I²C, CAN, ADC, PWM
                  CSI (or 21 additional GPIO pins), LCD display LVDS (or 36 additional GPIO pins)
                  7-17 GPIO pins (or 7-74 GPIO pins if CSI and LCD are re-purposed)
                  IR receiver
                  On board microphone

Overall I'd probably pick the Beaglebone Black as having the best GPIO/Low-level peripherals support (and very easy access to the pins).


Power

Raspberry Pi A: 500mA-1000mA
Raspberry Pi B: 700-1000mA
Raspberry Pi A+:  500mA-2000mA
Raspberry Pi B+: 600-2000mA
Beaglebone Black: 300–500 mA @5 V
Banana Pi: 200mA*-2000mA (*requires 700-800mA during boot)


Weight

Raspberry Pi A:  45 g (1.6 oz)
Raspberry Pi B:  45 g (1.6 oz)
Raspberry Pi A+:   23 g (0.81 oz)
Raspberry Pi B+:  45 g (1.6 oz)
Beaglebone Black: 39.68 g (1.400 oz)
Banana Pi:  48 g (1.7 oz)



My conclusion would be if it is light weight I needed, then I'd go with a Pro Trinket (2.6g/0.09oz), unless I needed a 1920x1080HD camera as well then it would be the Raspberry Pi A+ (23g/0.81oz) with a camera module (3g/0.11oz). If it was easily accessible GPIO that I needed, with loads of inputs and outputs I'd pick the Beaglebone Black (It is a great piece of open hardware) 7ADC is nice. And finally if it was shoving large amounts of data about fast, or processing that data, I'd pick the Banana Pi (With SATA 2.0, Gigabit Ethernet and 1GiB of RAM it is an impressive piece of kit) or it's newer incarnation of hardware the Banana Pro (with builtin WiFi).

There are larger communities built up around the Raspberry Pi and Beaglebone Black, than there is around the Banana Pi/Pro hardware.  So if you have a problem, sometimes you may have to solve it yourself rather than looking for a quick fix from someone else in the community  who had the same problem already.

Wednesday 12 November 2014

Banana Pi SATA 2.0 disk throughput test

Hardware Configuration:

Banana Pi-M1 1024MiB RAM, no overclocking
Inbuilt 10/100/1000 NIC is connected.
Top USB port is empty.
Bottom USB port is empty.
SATA disk connected via SATA cable to SATA port on BPi.
Harddisk is power from an external supply (R-Driver III).
No keyboard and no mouse.

The HDD that I'm using has an Internal write rate of about 100MiB/sec, so it is not a great disk for SATA performance testing, but it is the same make and model that I used for testing the Raspberry Pi USB disk throughput test.

 

Prerequisites:

apt-get install dosfstools
apt-get install expect expect-dev tcl8.6 tk8.6



ext2, ext3, ext4, vfat file system write tests 


I split a 2 TB disk into four equal sized partitions.

root@bananapi ~ # fdisk -l /dev/sda

Disk /dev/sda: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x5d3d4ef6

Device     Boot      Start        End   Sectors   Size Id Type
/dev/sda1             2048  976758783 976756736 465.8G 83 Linux
/dev/sda2        976758784 1953515519 976756736 465.8G 83 Linux
/dev/sda3       1953515520 2930272255 976756736 465.8G 83 Linux
/dev/sda4       2930272256 3907028991 976756736 465.8G  c W95 FAT32 (LBA)

root@bananapi ~ # mkfs.ext2 -L ext2 /dev/sda1
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 122094592 4k blocks and 30531584 inodes
Filesystem UUID: 35d529af-5e67-4f17-8c78-5af67a4f85f8
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000

Allocating group tables: done
Writing inode tables: done
Writing superblocks and filesystem accounting information: done

mkfs.ext2 -L ext2 /dev/sda1  0.65s user 31.41s system 12% cpu 4:18.17 total
root@bananapi ~ # mkfs.ext3 -L ext3 /dev/sda2
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 122094592 4k blocks and 30531584 inodes
Filesystem UUID: d0fe6f90-cc02-4d98-ba62-a704692edaf3
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

mkfs.ext3 -L ext2 /dev/sda2  0.81s user 33.67s system 13% cpu 4:20.11 total
root@bananapi ~ # mkfs.ext4 -L ext4 /dev/sda3
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 122094592 4k blocks and 30531584 inodes
Filesystem UUID: 02029d9e-70e3-4012-a217-fff6754fe0b8
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

root@bananapi ~ # mkfs.vfat -n VFAT /dev/sda4
mkfs.fat 3.0.26 (2014-03-07)
root@bananapi ~ # cd /media
root@bananapi /media # mkdir ext2 ext3 ext4 vfat
root@bananapi /media # cd
 






root@bananapi ~ # cat write-throughputtest.exp
#!/usr/bin/expect -f

set force_conservative 0  ;# set to 1 to force conservative mode even if
                          ;# script wasn't run conservatively originally
if {$force_conservative} {
        set send_slow {1 .1}
        proc send {ignore arg} {
                sleep .1
                exp_send -s -- $arg
        }
}


set timeout -1
spawn $env(SHELL)
match_max 100000
expect "root@bananapi"
send -- "script /root/output.txt\r"
expect "Script started, file is /root/output.txt\r"
send -- "mount /dev/sda1 /media/ext2\r"
expect "root@bananapi"
send -- "mount /dev/sda2 /media/ext3\r"
expect "root@bananapi"
send -- "mount /dev/sda3 /media/ext4\r"
expect "root@bananapi"
send -- "mount /dev/sda4 /media/vfat\r"
expect "root@bananapi"
send -- "/root/write-throughputtest.sh /media/ext2\r"
expect "root@bananapi"
send -- "/root/write-throughputtest.sh /media/ext3\r"
expect "root@bananapi"
send -- "/root/write-throughputtest.sh /media/ext4\r"
expect "root@bananapi"
send -- "/root/write-throughputtest.sh /media/vfat\r"
expect "root@bananapi"
send -- "exit\r"
expect "Script done, file is /root/output.txt\r"
send -- "exit\r"
expect eof
root@bananapi ~ #










root@bananapi ~ # cat write-throughputtest.sh
#!/bin/sh
DEST=$1

# 18 x 1GiB = 18GiB
# assuming maximum write SATA2 286MiB/sec this should take more than a minute
# assuming poor write speed of 5 MiB/sec this should take more than a hour
# either way one pass should happen within 12 hours
echo touch $DEST/testbegin-write-starttime
touch $DEST/testbegin-write-starttime
date
echo sync
sync
date

for BS in 8 16 32 64 128 256 \
        512 1024 2048 4096 8192 16384 \
        32768 65536 131072 262144 524288 1048576

do
 COUNT=`expr 1073741824 / $BS`
echo touch $DEST/${BS}b-write-starttime
 touch $DEST/${BS}b-write-starttime
date
echo dd if=/dev/zero of=$DEST/${BS}b-data bs=${BS} count=${COUNT}
 dd if=/dev/zero of=$DEST/${BS}b-data bs=${BS} count=${COUNT}
date
echo touch $DEST/${BS}b-write-endtime
 touch $DEST/${BS}b-write-endtime
date
echo sync
 sync
date
# any delay caused by sync will show up on next starttime
done

echo touch $DEST/testover-write-endtime
touch $DEST/testover-write-endtime
date

root@bananapi ~ #











root@bananapi ~ # cat read-throughputtest.sh
#!/bin/sh

SRCE=$1


# 18 x 1GiB = 18GiB
# assuming maximum read SATA2 286MB/sec this whould take just over a minute
# assuming poor read speed of 5 MiB/sec this should take just over a hour
# This script assumes that write-throughputtest.sh was run
# previously to generate the data files.

date
echo sync
sync
date

for BS in 8 16 32 64 128 256 \
        512 1024 2048 4096 8192 16384 \
        32768 65536 131072 262144 524288 1048576
do
 COUNT=`expr 1073741824 / $BS`
date

echo dd of=/dev/null if=$SRCE/${BS}b-data bs=${BS} count=${COUNT}
 dd of=/dev/null if=$SRCE/${BS}b-data bs=${BS} count=${COUNT}
date
echo sync
 sync
date
done


date
root@bananapi ~ #





I'm converting the results so that I can display them in MiB/sec instead of dd's default of MB/sec. Because I'm copying a Gigabyte of data with each block size all I need to do is divide 1024 by the number of seconds that it took to get the result in MiB/second.



root@bananapi ~ # grep bytes output.txt | grep copied | head -18
1073741824 bytes (1.1 GB) copied, 775.481 s, 1.4 MB/s
1073741824 bytes (1.1 GB) copied, 428.811 s, 2.5 MB/s
1073741824 bytes (1.1 GB) copied, 222.595 s, 4.8 MB/s
1073741824 bytes (1.1 GB) copied, 115.167 s, 9.3 MB/s
1073741824 bytes (1.1 GB) copied, 67.9903 s, 15.8 MB/s
1073741824 bytes (1.1 GB) copied, 43.2929 s, 24.8 MB/s
1073741824 bytes (1.1 GB) copied, 28.109 s, 38.2 MB/s
1073741824 bytes (1.1 GB) copied, 24.2247 s, 44.3 MB/s
1073741824 bytes (1.1 GB) copied, 23.847 s, 45.0 MB/s
1073741824 bytes (1.1 GB) copied, 23.8354 s, 45.0 MB/s
1073741824 bytes (1.1 GB) copied, 23.7234 s, 45.3 MB/s
1073741824 bytes (1.1 GB) copied, 23.8386 s, 45.0 MB/s
1073741824 bytes (1.1 GB) copied, 23.6681 s, 45.4 MB/s
1073741824 bytes (1.1 GB) copied, 24.1159 s, 44.5 MB/s
1073741824 bytes (1.1 GB) copied, 24.3767 s, 44.0 MB/s
1073741824 bytes (1.1 GB) copied, 24.477 s, 43.9 MB/s
1073741824 bytes (1.1 GB) copied, 24.8436 s, 43.2 MB/s
1073741824 bytes (1.1 GB) copied, 24.3786 s, 44.0 MB/s
root@bananapi ~ # grep bytes output.txt | grep copied |  awk '{printf "%3.1f\n", 1024/$6}' | head -18
1.3
2.4
4.6
8.9
15.1
23.7
36.4
42.3
42.9
43.0
43.2
43.0
43.3
42.5
42.0
41.8
41.2
42.0
root@bananapi ~ #


 Results

SATA disk performance check on Banana Pi SATA port.


Banana Pi SATA disk write results (spinning rust)
-----------------------------------------------------------
block             filesystem type
size   -------------------------------------------            
(bytes)ext2       ext3       ext4       vfat
8       1.3 MiB/s  0.6 MiB/s  0.6 MiB/s  1.1 MiB/s
16      2.4 MiB/s  1.1 MiB/s  1.1 MiB/s  2.1 MiB/s
32      4.6 MiB/s  2.1 MiB/s  2.1 MiB/s  3.9 MiB/s
64      8.9 MiB/s  4.0 MiB/s  4.1 MiB/s  7.3 MiB/s
128    15.1 MiB/s  7.6 MiB/s  7.9 MiB/s 11.9 MiB/s
256    23.7 MiB/s 13.0 MiB/s 12.5 MiB/s 16.7 MiB/s
512    36.4 MiB/s 21.3 MiB/s 23.2 MiB/s 23.0 MiB/s
1k     42.3 MiB/s 30.9 MiB/s 36.0 MiB/s 26.4 MiB/s
2k     42.9 MiB/s 36.2 MiB/s 43.8 MiB/s 28.7 MiB/s
4k     43.0 MiB/s 40.3 MiB/s 44.5 MiB/s 29.7 MiB/s
8k     43.2 MiB/s 41.0 MiB/s 44.2 MiB/s 30.6 MiB/s
16k    43.0 MiB/s 40.6 MiB/s 44.0 MiB/s 31.0 MiB/s
32k    43.3 MiB/s
37.5 MiB/s 44.0 MiB/s 30.2 MiB/s
64k    42.5 MiB/s 39.9 MiB/s 43.4 MiB/s 30.4 MiB/s
128k   42.0 MiB/s 39.9 MiB/s 42.3 MiB/s 30.1 MiB/s
256k   41.8 MiB/s 39.1 MiB/s 43.3 MiB/s 29.8 MiB/s
512k   41.2 MiB/s 38.9 MiB/s 43.0 MiB/s 30.6 MiB/s

1M     42.0
MiB/s 39.6 MiB/s 43.5 MiB/s 30.0 MiB/s


Banana Pi SATA disk read results (spinning rust)
-----------------------------------------------------------
block             filesystem type
size   -------------------------------------------           
(bytes)ext2       ext3       ext4       vfat
8        2.1MiB/s   2.1MiB/s   2.0MiB/s   2.0MiB/s
16       4.0MiB/s   4.1MiB/s   4.1MiB/s   4.0MiB/s
32       8.7MiB/s   8.6MiB/s  
8.5MiB/s   8.6MiB/s
64     
17.0MiB/s  16.9MiB/s  17.0MiB/s  16.9MiB/s
128     31.3MiB/s  31.2MiB/s 
31.5MiB/s  30.5MiB/s
256     54.8MiB/s  54.2MiB/s 
55.1MiB/s  52.4MiB/s
512     84.6MiB/s 100.4MiB/s 
83.9MiB/s  72.8MiB/s
1k     108.7MiB/s
100.4MiB/s  86.5MiB/s  74.2MiB/s
2k     107.7MiB/s  99.6
MiB/s  87.2MiB/s  73.8MiB/s
4k     109.7MiB/s 100.4
MiB/s  86.3MiB/s  72.6MiB/s
8k     109.7MiB/s 100.8
MiB/s  87.7MiB/s  73.1MiB/s
16k    109.8MiB/s
100.4MiB/s  86.6MiB/s  74.1MiB/s
32k    108.8MiB/s  98.0
MiB/s  87.6MiB/s  73.5MiB/s
64k    109.2MiB/s 100.4
MiB/s  86.0MiB/s  72.7MiB/s
128k   109.3MiB/s
100.7MiB/s  85.7MiB/s  73.2MiB/s
256k   108.7MiB/s
100.5MiB/s  86.8MiB/s  74.1MiB/s
512k   108.9MiB/s 
99.6MiB/s  88.1MiB/s  73.3MiB/s
1M     109.1MiB/s  99.2MiB/s 
86.7MiB/s  72.9MiB/s




I decided to run the tests again with an old 128GB SSD (write performance will be OKish because it is used, but read performance should be better than spinning rust). But to avoid killing it (small writes cause SSD's to fail prematurely) I started the write testing at 4K block size.The read test block size does not matter at all, SSD's always fail due to running out of writes (3000-5000 per block) long before any wear due to reads can happen. The reason I ran the tests again with a SSD was because I felt that the limiting factor was the Harddisk's poor read/write performance and not any limit of the Banana Pi's SATA 2.0 port.











Banana Pi SATA disk write results (SSD)
-----------------------------------------------------------
block             filesystem type
size   -------------------------------------------            
(bytes)ext2       ext3       ext4       vfat
4k     44.9 MiB/s 40.0 MiB/s 42.5 MiB/s 29.0 MiB/s
8k     45.3 MiB/s 41.0 MiB/s 42.5 MiB/s 29.8 MiB/s
16k    44.2 MiB/s 41.0 MiB/s 42.7 MiB/s 29.5 MiB/s
32k    43.9 MiB/s
41.7 MiB/s 42.4 MiB/s 29.3 MiB/s
64k    43.6 MiB/s 40.4 MiB/s 41.9 MiB/s 29.0 MiB/s
128k   42.5 MiB/s 39.5 MiB/s 42.1 MiB/s 28.3 MiB/s
256k   42.6 MiB/s 39.9 MiB/s 41.7 MiB/s 28.9 MiB/s
512k   43.8 MiB/s 39.7 MiB/s 
43.0 MiB/s 30.9 MiB/s
1M     43.7
MiB/s 40.3 MiB/s 41.7 MiB/s 32.0 MiB/s

Banana Pi SATA disk read results (SSD)
-----------------------------------------------------------
block             filesystem type
size   -------------------------------------------           
(bytes)ext2       ext3       ext4       vfat
8        2.0MiB/s   2.0MiB/s   2.1MiB/s   2.1MiB/s
16       4.2MiB/s   4.2MiB/s   4.2MiB/s   4.2MiB/s
32       9.0MiB/s   8.9MiB/s  
9.1MiB/s   8.9MiB/s
64     
17.2MiB/s  17.1MiB/s  17.0MiB/s  17.0MiB/s
128     31.4MiB/s  31.6MiB/s 
31.5MiB/s  31.1MiB/s
256     53.7MiB/s  54.7MiB/s 
55.0MiB/s  55.0MiB/s
512     83.6MiB/s  85.8MiB/s 
86.6MiB/s  85.8MiB/s
1k     115.6MiB/s
126.0MiB/s 123.6MiB/s 121.9MiB/s
2k     139.4MiB/s 1
51.5MiB/s 154.0MiB/s 152.5MiB/s
4k     160.3MiB/s 181.1
MiB/s 175.1MiB/s 180.8MiB/s
8k     185.1MiB/s 1
86.0MiB/s 180.4MiB/s 183.9MiB/s
16k    182.8MiB/s
183.9MiB/s 176.4MiB/s 184.5MiB/s
32k    173.2MiB/s 161.3
MiB/s 168.8MiB/s 171.2MiB/s
64k    163.0MiB/s 151.4
MiB/s 158.6MiB/s 161.3MiB/s
128k   159.0MiB/s
147.2MiB/s 154.0MiB/s 156.5MiB/s
256k   156.0MiB/s
147.3MiB/s 152.0MiB/s 155.4MiB/s
512k   156.6MiB/s
145.2MiB/s 153.0MiB/s 156.3MiB/s
1M     157.9MiB/s 148.1MiB/s
154.8MiB/s 156.4MiB/s


Since the throughput is more than 150MB/sec, it does confirm that the SATA port in the Banana Pi is SATA 2.0. And I suspect that it could get closer to the SATA 2.0 limit of 300MB/sec if I used a brand new SSD. I have to admit that I am so much more impressed by a Banana Pi especially when compared to a Raspberry Pi. Especially for pushing large amounts of data about fast, it is brilliant hardware.