Pages

Friday, 31 May 2013

Getting started with OpenMP

In the previous posts, about creating logging software for the boat trial, I mentioned the fact we were logging GPS and stereo images. This was done using OpenMP to parallelise the processing so that the program wasn't hanging around for a GPS update causing delay between image samples.

This is a quick guide on how to get OpenMP going.

My first mistake was thinking it was something that needed to be installed and configured. It's just a switch in Visual Studio 2010. Go to the project properties page. C/C++  > Language > OpenMP Support > Yes.



Now you'll be amazed how easy it is to get a simple program working that uses two cores...Here's a snippet from the logger that capture GPS data using 1 core and images from a camera using the other. I've highlighted the important lines of code and briefly outlined what their functions are.

#include <iostream>
#include <stdio.h>
#include <string>
#include <Windows.h>
#include "SerialGPS.h"
#include <omp.h>

#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace std;

int main( int argc, char** argv )
{  
  //set up the com port 
  SerialGPS GPS("COM6",4800);
  SerialGPS::GPGGA GPSData={};
  
  if (!GPS.isReady()) { return 0;  }
  cout << "GPS Connected Status = " << GPS.isReady() << endl;
  
  int gpsReadCounter=0;
  
  //create the video capture object
  cv::VideoCapture cap1;
  cap1.open(0);

  cv::Mat Frame;
  
  //define the shared variables between threads
  #pragma omp parallel sections shared(GPSData) {

    //////// FIRST CPU THREAD ////////
    #pragma omp section
    {
      for (int i = 0; i<100; i++) {
        cap1 >> Frame;
        cv::imshow("Cam",Frame);
        cv::waitKey(33);
        cout << "   GPS Data Time = " << GPSData.GPStime << endl;
      }
    }

    //////// SECOND CPU THREAD ////////
    #pragma omp section
    {

      for (int i = 0; i<100; i++) {
        if (GPS.update(GPSData, FORCE_UPDATE)) {
          cout << " T=" << GPSData.GPStime << " La=" << GPSData.Lat << " Lo=" << GPSData.Lon << endl;
        } else {
          cout << "Error Count = " << GPS.getErrorCount() << "  ";
          GPS.displayRAW();
          cout << endl; 
        }
      }
    }
  }
}


- Make sure to #include <omp.h>
- The line #pragma omp parallel sections shared(GPSData) enables the data structure, GPSData, to be accessible from either thread.
- The lines #pragma omp section define the code that is to run on an individual thread
- GPSData gets populated from the call GPS.update(GPSData, FORCE_UPDATE)
- Since we initialised all the values to 0 with SerialGPS::GPGGA GPSData={}; it doesn't matter if the camera thread gets to reading the data before the GPS update thread has populated the structure with any meaningful values.
- As soon as the the GPS thread receives a valid signal and updates GPSData accordingly this data is accessible from the camera thread.
- Note that while both threads loop while i<100, this i value is local to each thread. It's very likely that one thread will finish before the other as no synchronization is taking place here, we're just offloading the GPS updates so that it doesn't interfere with the image sampling and allows use to simply tag an image with the latest good GPS values.

This example broadly gives you an idea of how to use two threads and share a variable between them.

There's a handy OpenMP cheatsheet here (http://openmp.org/mp-documents/OpenMP3.1-CCard.pdf)

No comments:

Post a Comment