absdevsreader.cpp 10.6 KB

/*-----------------------------------------------------------*/

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <cstring>
#include "cputopology.hpp"

/*-----------------------------------------------------------*/

int main(int argc, char** argv)
{
    if (argc != 3)
    {
       std::cerr << "Usage: " << argv[0]
                 << " <Abstract devices file> <verbosity (0|1)>"
                 << std::endl;
       exit(EXIT_FAILURE);
    }

    std::string abstractDevicesFile = argv[1];
    bool verbosity = atoi(argv[2]);

    std::ifstream absDevices(abstractDevicesFile.c_str());
    if (!absDevices.is_open())
    {
       std::cerr << "Unable to open "
                 << abstractDevicesFile
                 << std::endl;
       exit(EXIT_FAILURE);
    }

    unsigned int numLogicalCPUs, numPhysicalCPUs;
    int rc = hcl::topology::getNumLogicalCpus(&numLogicalCPUs);
    if (rc != 0)
    {
       std::cerr << "Error to get number of logical cores..."
                 << std::endl;
       exit(EXIT_FAILURE);
    }

    rc = hcl::topology::getNumPhysicalCpus(&numPhysicalCPUs);
    if (rc != 0)
    {
       std::cerr << "Error to get number of physical cores..."
                 << std::endl;
       exit(EXIT_FAILURE);
    }

    std::cout << "Number of logical cores " << numLogicalCPUs
              << std::endl;
    std::cout << "Number of physical cores " << numPhysicalCPUs
              << std::endl;

    std::vector<unsigned int> nCoresList;
    std::vector<std::string> coresList;
    std::vector<std::string> abstractDevicesTable;
    std::vector<std::string> powerPlatforms;

    /*
     * We always include the CPU
     */
    powerPlatforms.push_back("CPUPCM");

    unsigned int numCoresBound = 0;
    std::string line;
    nCoresList.push_back(numCoresBound);
    while (std::getline(absDevices, line))
    {
       /*
        * Ignore comment line...
        */
       if (line.find('#') != std::string::npos)
       {
          continue;
       }

       std::stringstream ss(line);
       std::string coreListing;
       std::string gemmKernel;
       unsigned int numMPIProcesses;
       std::string numOMPThreads;

       ss >> coreListing 
          >> gemmKernel
          >> numMPIProcesses
          >> numOMPThreads;

       if (verbosity)
       {
          std::cout << coreListing << " "
                    << gemmKernel << " "
                    << numMPIProcesses << " "
                    << numOMPThreads << std::endl;
       }

       if (coreListing.find('-') == std::string::npos)
       {
          /*
           * Simplest case, just one core to bind.
           */
          if (coreListing.find(',') == std::string::npos)
          {
             coresList.push_back(coreListing);
             numCoresBound++;
             nCoresList.push_back(numCoresBound);
          }
          else
          {
             /*
              * There are comma separated list of cores...
              */
             char* cstr = new char[coreListing.length() + 1];
             strcpy(cstr, coreListing.c_str());
             char* tok = strtok(cstr, ",");
             while (tok != NULL)
             {
                 coresList.push_back(tok);
                 numCoresBound++;
                 tok = strtok(NULL, ",");
             }
             delete []cstr;
             nCoresList.push_back(numCoresBound);
          }
       }
       else
       {
          /*
           * Just one range token...
           */
          if (coreListing.find(',') == std::string::npos)
          {
             std::vector<unsigned int> coreRange;
             char* cstr = new char[coreListing.length() + 1];
             strcpy(cstr, coreListing.c_str());
             char* tok = strtok(cstr, "-");
             while (tok != NULL)
             {
                 coreRange.push_back(atoi(tok));
                 tok = strtok(NULL, ",");
             }
             delete []cstr;

             /*
              * We expect just two elements in core range...
              */
             unsigned int start = coreRange[0];
             unsigned int end = coreRange[1];

             /*
              * The MPI processes divide the cores equally amongst them...
              */
             for (size_t e = 0; e < numMPIProcesses; e++)
             {
                 numCoresBound += (end - start + 1) / numMPIProcesses;
                 nCoresList.push_back(numCoresBound);
             }

             for (size_t e = start; e <= end; e++)
             {
                 coresList.push_back(std::to_string(e));
             }
          }
          else
          {
             /*
              * A mix of - and ,
              */
             char* cstr1 = (char*)coreListing.c_str();
             char* saveptr1, *saveptr2;

             char* tok = strtok_r(cstr1, ",", &saveptr1);
             while (tok != NULL)
             {
                 std::cout << tok << std::endl;
                 char* tok2 = strtok_r(tok, "-", &saveptr2);
                 std::vector<unsigned int> coreRange;
                 while (tok2 != NULL)
                 {
                     std::cout << tok2 << std::endl;
                     coreRange.push_back(atoi(tok2));
                     tok2 = strtok_r(NULL, "-", &saveptr2);
                 }

                 /*
                  * We expect just two elements in core range...
                  */
                 unsigned int start = coreRange[0];
                 unsigned int end = coreRange[1];

                 /*
                  * The MPI processes divide the cores equally amongst them...
                  */
                 for (size_t e = 0; e < numMPIProcesses; e++)
                 {
                     numCoresBound += (end - start + 1) / numMPIProcesses;
                     nCoresList.push_back(numCoresBound);
                 }

                 for (size_t e = start; e <= end; e++)
                 {
                     coresList.push_back(std::to_string(e));
                 }

                 tok = strtok_r(NULL, ",", &saveptr1);
             }
          }
       }

       if (gemmKernel.find("CPU,GPU") != std::string::npos)
       {
          powerPlatforms.push_back("GPULITE");
       }

       if (gemmKernel.find("CPU,PHI") != std::string::npos)
       {
          powerPlatforms.push_back("PHILITE");
       }

       if (gemmKernel.find("CPU,FPGA") != std::string::npos)
       {
          powerPlatforms.push_back("FPGA");
       }

       for (size_t p = 0; p < numMPIProcesses; p++)
       {
          std::stringstream ssOut;

          if (gemmKernel.find("CPU") != std::string::npos)
          {
             ssOut << "cpuinit, cpudgemm, cpudestroy";
          }

          if (gemmKernel.find("GPU") != std::string::npos)
          {
             ssOut << "gpuinit, gpudgemm, gpudestroy";
          }

          if (gemmKernel.find("PHI") != std::string::npos)
          {
             ssOut << "phiinit, phidgemm, phidestroy";
          }

          if (gemmKernel.find("FPGA") != std::string::npos)
          {
             ssOut << "fpgainit, fpgadgemm, fpgadestroy";
          }

          if (numOMPThreads.find('-') != std::string::npos)
          {
             ssOut << ", 0";
          }
          else
          {
             ssOut << ", " << numOMPThreads;
          }

          abstractDevicesTable.push_back(ssOut.str());
       }
    }

    if (numCoresBound > numLogicalCPUs)
    {
       std::cerr << "Number of cores bound "
                 << numCoresBound << " exceeded "
                 << "the allowed number of logical cores."
                 << std::endl;
       exit(EXIT_FAILURE);
    }

    if (numCoresBound > numPhysicalCPUs)
    {
       std::cerr << "Warning: Number of cores bound exceeded "
                 << "the allowed number of physical cores."
                 << std::endl;
    }

    /*
     * Spit out the abstract devices table...
     */
    std::ofstream abstractDevicesOFile;
    abstractDevicesOFile.open("absdevs.c");

    abstractDevicesOFile << "\n/*----------------------------------"
                         << "------------------------------------------*/\n"
                         << std::endl;
    abstractDevicesOFile << "#include \"absdevs.h\"" << std::endl;
    abstractDevicesOFile << "\n/*----------------------------------"
                         << "------------------------------------------*/\n"
                         << std::endl;

    /*
     * Core bindings here...
     */
    abstractDevicesOFile << "const unsigned int hcl_coreindex[] = {"
                         << std::endl;
    size_t n = nCoresList.size();
    for (size_t e = 0; e < n; e++)
    {
       if (e == (n-1))
       {
          abstractDevicesOFile << nCoresList[e];
       }
       else
       {
          abstractDevicesOFile << nCoresList[e] << ",";
       }
    }
    abstractDevicesOFile << "\n};" << std::endl;

    abstractDevicesOFile << "const unsigned int hcl_corebindings[] = {"
                         << std::endl;
    n = coresList.size();
    for (size_t e = 0; e < n; e++)
    {
       if (e == (n-1))
       {
          abstractDevicesOFile << coresList[e];
       }
       else
       {
          abstractDevicesOFile << coresList[e] << ",";
       }
    }
    abstractDevicesOFile << "\n};" << std::endl;

    abstractDevicesOFile << "\n/*----------------------------------"
                         << "------------------------------------------*/\n"
                         << std::endl;
    abstractDevicesOFile.close();

    std::ofstream abstractDevicesPowersOFile;
    abstractDevicesPowersOFile.open("absdevpowers.c");

    /*
     * Compute Platforms here...
     */
    abstractDevicesPowersOFile << "\n/*----------------------------------"
                         << "------------------------------------------*/\n"
                         << std::endl;

    abstractDevicesPowersOFile << "const char* hcl_powerplatforms[] = {"
                         << std::endl;
    n = powerPlatforms.size();
    for (size_t e = 0; e < n; e++)
    {
       if (e == (n-1))
       {
          abstractDevicesPowersOFile << "\"" << powerPlatforms[e] << "\"";
       }
       else
       {
          abstractDevicesPowersOFile << "\"" << powerPlatforms[e] << "\",";
       }
    }
    abstractDevicesPowersOFile << "\n};" << std::endl;

    abstractDevicesPowersOFile << "\n/*----------------------------------"
                         << "------------------------------------------*/\n"
                         << std::endl;

    abstractDevicesPowersOFile.close();

    std::cout << "Abstract devices file successfully parsed" << std::endl;

    exit(EXIT_SUCCESS);
}

/*-----------------------------------------------------------*/