From a92967fa7c345d4e9b0ed7207194fe884c3b31fd Mon Sep 17 00:00:00 2001 From: David Brodski Date: Thu, 18 Sep 2014 10:28:23 +0200 Subject: [PATCH] Added benchmark define some code cleanup and speedups Former-commit-id: 8254c34e1d10c598e127f46635ae6bafcb97087a --- libsrc/leddevice/LedDeviceWS2812b.cpp | 68 ++++++++++++++++++++------- libsrc/leddevice/LedDeviceWS2812b.h | 11 ++++- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/libsrc/leddevice/LedDeviceWS2812b.cpp b/libsrc/leddevice/LedDeviceWS2812b.cpp index 2abbb1b9..bcd9f48d 100644 --- a/libsrc/leddevice/LedDeviceWS2812b.cpp +++ b/libsrc/leddevice/LedDeviceWS2812b.cpp @@ -14,6 +14,10 @@ //#include //#include +#ifdef BENCHMARK + #include +#endif + // hyperion local includes #include "LedDeviceWS2812b.h" @@ -230,31 +234,40 @@ LedDeviceWS2812b::LedDeviceWS2812b() : LedDevice(), mLedCount(0) + +#ifdef BENCHMARK + , + runCount(0), + combinedNseconds(0), + shortestNseconds(2147483647) +#endif + { + //shortestNseconds = 2147483647; // Init PWM generator and clear LED buffer initHardware(); //clearLEDBuffer(); + printf("WS2812b init finished \n"); } int LedDeviceWS2812b::write(const std::vector &ledValues) { +#ifdef BENCHMARK + timespec timeStart; + timespec timeEnd; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timeStart); +#endif + mLedCount = ledValues.size(); //printf("Set leds, number: %d\n", mLedCount); -// const unsigned dataLen = ledValues.size() * sizeof(ColorRgb); -// const uint8_t * dataPtr = reinterpret_cast(ledValues.data()); - // Clear out the PWM buffer // Disabled, because we will overwrite the buffer anyway. // Read data from LEDBuffer[], translate it into wire format, and write to PWMWaveform -// unsigned int LEDBuffeWordPos = 0; -// unsigned int PWMWaveformBitPos = 0; unsigned int colorBits = 0; // Holds the GRB color before conversion to wire bit pattern - unsigned char colorBit = 0; // Holds current bit out of colorBits to be processed unsigned int wireBit = 0; // Holds the current bit we will set in PWMWaveform -// Color_t color; for(size_t i=0; i &ledValues) // Iterate through color bits to get wire bits for(int j=23; j>=0; j--) { - colorBit = (colorBits & (1 << j)) ? 1 : 0; + unsigned char colorBit = (colorBits & (1 << j)) ? 1 : 0; // Holds current bit out of colorBits to be processed + + setPWMBit(wireBit++, 1); + setPWMBit(wireBit++, colorBit); + setPWMBit(wireBit++, 0); + /* old code for better understanding switch(colorBit) { case 1: //wireBits = 0b110; // High, High, Low @@ -279,13 +297,13 @@ int LedDeviceWS2812b::write(const std::vector &ledValues) setPWMBit(wireBit++, 0); setPWMBit(wireBit++, 0); break; - } + }*/ } } // Copy PWM waveform to DMA's data buffer //printf("Copying %d words to DMA data buffer\n", NUM_DATA_WORDS); - ctl = (struct control_data_s *)virtbase; + struct control_data_s *ctl = (struct control_data_s *)virtbase; dma_cb_t *cbp = ctl->cb; // 72 bits per pixel / 32 bits per word = 2.25 words per pixel @@ -298,10 +316,10 @@ int LedDeviceWS2812b::write(const std::vector &ledValues) // This block is a major CPU hog when there are lots of pixels to be transmitted. // It would go quicker with DMA. - for(unsigned int i = 0; i < (cbp->length / 4); i++) { - ctl->sample[i] = PWMWaveform[i]; - } - +// for(unsigned int i = 0; i < (cbp->length / 4); i++) { +// ctl->sample[i] = PWMWaveform[i]; +// } + memcpy ( ctl->sample, PWMWaveform, cbp->length ); // memcpy does the same and is potentially faster // Enable DMA and PWM engines, which should now send the data startTransfer(); @@ -312,6 +330,20 @@ int LedDeviceWS2812b::write(const std::vector &ledValues) //printf("Delay for %d μSec\n", (int)bitTimeUSec); //usleep((int)bitTimeUSec); +#ifdef BENCHMARK + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timeEnd); + timespec result; + + result.tv_sec = timeEnd.tv_sec - timeStart.tv_sec; + result.tv_nsec = timeEnd.tv_nsec - timeStart.tv_nsec; + if (result.tv_nsec < 0) { + result.tv_nsec = 1e9 - result.tv_nsec; + result.tv_sec -= 1; + } + runCount ++; + combinedNseconds += result.tv_nsec; + shortestNseconds = result.tv_nsec < shortestNseconds ? result.tv_nsec : shortestNseconds; +#endif return 0; } @@ -325,6 +357,10 @@ LedDeviceWS2812b::~LedDeviceWS2812b() // Exit cleanly, freeing memory and stopping the DMA & PWM engines // We trap all signals (including Ctrl+C), so even if you don't get here, it terminates correctly terminate(0); +#ifdef BENCHMARK + printf("WS2812b Benchmark results: Runs %d - Avarage %lu (n) - Minimum %ld (n)\n", + runCount, (runCount > 0 ? combinedNseconds / runCount : 0), shortestNseconds); +#endif } @@ -576,7 +612,7 @@ void LedDeviceWS2812b::initHardware() { // Set up control block // --------------------------------------------------------------- - ctl = (struct control_data_s *)virtbase; + struct control_data_s *ctl = (struct control_data_s *)virtbase; dma_cb_t *cbp = ctl->cb; // FIXME: Change this to use DEFINEs unsigned int phys_pwm_fifo_addr = 0x7e20c000 + 0x18; @@ -724,7 +760,7 @@ void LedDeviceWS2812b::initHardware() { // Begin the transfer void LedDeviceWS2812b::startTransfer() { // Enable DMA - dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(ctl->cb); + dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(((struct control_data_s *) virtbase)->cb); dma_reg[DMA_CS] = DMA_CS_CONFIGWORD | (1 << DMA_CS_ACTIVE); usleep(100); diff --git a/libsrc/leddevice/LedDeviceWS2812b.h b/libsrc/leddevice/LedDeviceWS2812b.h index 65351056..79216b9a 100644 --- a/libsrc/leddevice/LedDeviceWS2812b.h +++ b/libsrc/leddevice/LedDeviceWS2812b.h @@ -101,6 +101,7 @@ // Hyperion includes #include +//#define BENCHMARK // The page map contains pointers to memory that we will allocate below. It uses two pointers // per address. This is because the software (this program) deals only in virtual addresses, @@ -150,7 +151,7 @@ private: /// the number of leds (needed when switching off) size_t mLedCount; - page_map_t *page_map; // This will hold the page map, which we'll allocate below + page_map_t *page_map; // This will hold the page map, which we'll allocate uint8_t *virtbase; // Pointer to some virtual memory that will be allocated volatile unsigned int *pwm_reg; // PWM controller register set @@ -174,7 +175,7 @@ private: uint32_t sample[NUM_DATA_WORDS]; }; - struct control_data_s *ctl; + //struct control_data_s *ctl; // PWM waveform buffer (in words), 16 32-bit words are enough to hold 170 wire bits. // That's OK if we only transmit from the FIFO, but for DMA, we will use a much larger size. @@ -193,6 +194,12 @@ private: void fatal(const char *fmt, ...); void * map_peripheral(uint32_t base, uint32_t len); void printBinary(unsigned int i, unsigned int bits); + +#ifdef BENCHMARK + unsigned int runCount; + long combinedNseconds; + long shortestNseconds; +#endif };