TensorRT/parsers/common/parserUtils.h源碼研讀

TensorRT/parsers/common/parserUtils.h源碼研讀

  • TensorRT/parsers/common/parserUtils.h
  • multiline macro
  • overload << operator
  • \_MSC_VER
  • \_\_QNX__
  • sysconf
  • MEMORYSTATUSEX及GlobalMemoryStatusEx
  • 參考連結

TensorRT/parsers/common/parserUtils.h

/* 
 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TRT_PARSER_UTILS_H
#define TRT_PARSER_UTILS_H

#include 
#include 
#include 
#include 
#include 
#include 

#ifndef _MSC_VER
#include 
#else
#define NOMINMAX
#include 
#endif

#include "NvInfer.h"

namespace parserutils
{
//輸出parserName相關的錯誤訊息,優先使用getLogger()來輸出,如果找不到,則使用std:cerr來輸出
#define RETURN_AND_LOG_ERROR_IMPL(ret, message, parserName)                                             \
    do                                                                                                  \
    {                                                                                                   \
        std::string errorMsg = parserName + std::string{message};                                       \
        if (getLogger()) getLogger()->log(nvinfer1::ILogger::Severity::kERROR, errorMsg.c_str());       \
        else std::cerr << "WARNING: Logger not found, logging to stderr.\n" << errorMsg << std::endl;   \
        return (ret);                                                                                   \
    } while (0)

// Helper function to compute unpadded volume of a Dims (1 if 0 dimensional)
//計算Dims各維的乘積,即體積
inline int64_t volume(const nvinfer1::Dims& d)
{
    int64_t v = 1;
    for (int64_t i = 0; i < d.nbDims; i++)
        v *= d.d[i];
    return v;
}

//在Unix及Windows系統下,輸出當前記憶體的使用情況
// Show some debugging output about how much memory is free
inline void printMem(const char* where)
{
#if !defined _MSC_VER && !defined __QNX__
//代表是一般的Unix系統?
    const unsigned mb = 1024 * 1024;
    //實體記憶體的page數量
    auto pages = static_cast<uint64_t>(sysconf(_SC_PHYS_PAGES));
    //當前實體記憶體中空著的page數量
    auto avPages = static_cast<uint64_t>(sysconf(_SC_AVPHYS_PAGES));
    //page的大小,單位是byte
    auto pageSize = static_cast<uint64_t>(sysconf(_SC_PAGE_SIZE));
    //輸出當前空著的記憶體大小及總記憶體大小
    std::cout << "   (memory) " << where << " : Free(MB) = " << avPages * pageSize / mb << " total(MB)=" << pages * pageSize / mb << std::endl;
#elif !defined __QNX__
//代表是Windows系統
    const unsigned mb = 1024 * 1024;
    MEMORYSTATUSEX statex;
    //在呼叫GlobalMemoryStatusEx前須設定好dwLength
    statex.dwLength = sizeof(statex);
    //填滿statex資料結構
    GlobalMemoryStatusEx(&statex);
    std::cout << "   (memory) " << where << " : Free(MB) = " << statex.ullAvailPhys / mb << " total(MB)=" << statex.ullTotalPhys / mb << std::endl;
#endif
}

//回傳資料型別的大小
// Compute size of datatypes
inline unsigned int elementSize(nvinfer1::DataType t)
{
    switch (t)
    {
    case nvinfer1::DataType::kINT32: return 4;
    case nvinfer1::DataType::kFLOAT: return 4;
    case nvinfer1::DataType::kHALF: return 2;
    case nvinfer1::DataType::kINT8: return 1;
    }
    //如果參數t不是上面任一種型別就會報錯
    assert(0);
    return 0;
}

//將nvinfer1::Dims轉成人看得懂的形式輸出
inline std::ostream& operator<<(std::ostream& o, const nvinfer1::Dims& dims)
{
    o << "[";
    for (int i = 0; i < dims.nbDims; i++)
        //如果i為0則不用加逗號
        o << (i ? "," : "") << dims.d[i];
    o << "]";
    return o;
}

//將nvinfer1::DataType轉成人看得懂的形式輸出
inline std::ostream& operator<<(std::ostream& o, nvinfer1::DataType dt)
{
    switch (dt)
    {
    case nvinfer1::DataType::kINT32: o << "Int32"; break;
    case nvinfer1::DataType::kFLOAT: o << "Float"; break;
    case nvinfer1::DataType::kHALF: o << "Half"; break;
    case nvinfer1::DataType::kINT8: o << "Int8"; break;
    }
    return o;
}

/*
nvinfer1::DimsCHW
定義於TensorRT/include/NvInfer.h
*/
//從Dims中抽取CHW三維的長度後回傳
inline nvinfer1::DimsCHW getCHW(const nvinfer1::Dims& d)
{
    assert(d.nbDims >= 3);
    //因為CHW必為末三維
    return nvinfer1::DimsCHW(d.d[d.nbDims - 3], d.d[d.nbDims - 2], d.d[d.nbDims - 1]);
}

/*
獲取Dims的末三維,如果Dims的長度小於三,就從前面用filter這個數字來補上?
*/
inline nvinfer1::DimsCHW getCHWWithExpansion(const nvinfer1::Dims& d, int filler)
{
    if (d.nbDims == 0)
        return nvinfer1::DimsCHW(filler, filler, filler);
    else if (d.nbDims == 1)
        return nvinfer1::DimsCHW(filler, filler, d.d[0]);
    else if (d.nbDims == 2)
        return nvinfer1::DimsCHW(filler, d.d[0], d.d[1]);
    else
        return nvinfer1::DimsCHW(d.d[d.nbDims - 3], d.d[d.nbDims - 2], d.d[d.nbDims - 1]);
}

/*
因為Dims的後三維必為CHW,
所以這裡將倒數第三維之前的所有維度給合併成一個維度,
當作batch size
*/
inline int combineIndexDimensions(int batchSize, const nvinfer1::Dims& d)
{
    int x = batchSize;
    for (int i = 0; i < d.nbDims - 3; i++)
        x *= d.d[i];
    return x;
}

//無條件進位的除法
template <typename A, typename B>
inline A divUp(A m, B n)
{
    return (m + n - 1) / n;
}

} // namespace parserhelper

#endif // PARSER_HELPER_H

multiline macro

觀察RETURN_AND_LOG_ERROR_IMPL這個macro,可以發現兩個特別之處,一是在除最後一行外的每行末尾都加上了\,二是使用do{} while(0)這個看似沒用的敍述來包住函數的主要內容。有關這兩點,詳見C multiline macro。

overload << operator

這個檔案中對<<進行了兩次overload,分別用於輸出nvinfer1::Dimsnvinfer1::DataType型別的物件,詳見C++ Overload stream insertion operator and stream extraction operator。

_MSC_VER

詳見C predefined macros __FILE__,__LINE__,__func__。

__QNX__

printMem函數裡用到了__QNX__這個macro。

根據Wiki - QNX,QNX是一個面向嵌入式系統的類Unix作業系統。

而根據Pre-defined Compiler Macros,在QNX 4.x作業系統上,編譯器會有預定義的macro__QNX__

sysconf

printMem函數裡用到了sysconf這個函數。

根據Linux Programmer’s Manual - SYSCONF(3),sysconf函數的簽名為:

#include 

long sysconf(int name);

其作用為:

get configuration information at run time

即獲取程式運行時的config資訊。

以下是printMem中用到的sysconf的參數:

  • _SC_PHYS_PAGES:實體記憶體的page數量
  • _SC_AVPHYS_PAGES:當前實體記憶體中空著的page數量
  • _SC_PAGE_SIZE:page的大小,單位是byte

MEMORYSTATUSEX及GlobalMemoryStatusEx

根據sysinfoapi.h header,Windows作業系統下的sysinfoapi.h檔裡,定義了MEMORYSTATUSEX資料結構及GlobalMemoryStatusEx函數。

而根據MEMORYSTATUSEX structure:

Contains information about the current state of both physical and 
virtual memory, including extended memory. 
The GlobalMemoryStatusEx function stores information in this structure.

這個資料結構裡記錄了實體及虛擬記憶體(包含了擴展記憶體)的當前狀態。GlobalMemoryStatusEx函數則用於將資訊存入這個資料結構中。

以下為MEMORYSTATUSEX裡的變數:

  • dwLength:記錄了MEMORYSTATUSEX資料結構本身的大小。在呼叫GlobalMemoryStatusEx之前必須將這個值設定好。
  • ullAvailPhys:當前空著的實體記憶體的大小,單位是byte
  • ullTotalPhys:實體記憶體的大小,單位是byte

根據GlobalMemoryStatusEx function,GlobalMemoryStatusEx函數的簽名為:

BOOL GlobalMemoryStatusEx(
  LPMEMORYSTATUSEX lpBuffer
);

其作用為:

Retrieves information about the system's current usage of 
both physical and virtual memory.

即獲取當前系統中實體及虛擬記憶體的使用情況。

參考連結

C multiline macro

C++ Overload stream insertion operator and stream extraction operator

C predefined macros __FILE__,__LINE__,__func__

Wiki - QNX

Pre-defined Compiler Macros

Linux Programmer’s Manual - SYSCONF(3)

sysinfoapi.h header

MEMORYSTATUSEX structure

GlobalMemoryStatusEx function

你可能感兴趣的:(TensorRT源碼研讀筆記)