LoginSignup
2
1

More than 3 years have passed since last update.

Halideでスタティックライブラリを作る・使う

Posted at

Halideは画像処理記述用のDSLです。
どういったものかは公式ページをご覧いただくか、福嶋先生がある程度の日本語資料を投稿されていますので、そちらを参照ください。

HalideではJITコンパイルによる動作だけではなく、記述したFuncを静的ライブラリとしてAOTコンパイルし、既存のプログラムに組み込むことも可能です。

基本的な作り方と使い方

gen_staticlib.cpp
#include <Halide.h>

void Gen_StaticLib()
{
    using namespace Halide;

    ImageParam input(type_of<uint8_t>(), 3);  // x,y,ch 3次元
    Param<float> mul;

    Func brighter;
    Var x, y, ch;
    brighter(x, y, ch) = cast<uint8_t>(min(input(x, y, ch) * mul, 255));
    brighter.parallel(y);

    brighter.compile_to_static_library(
        "brighter",     // .lib のファイル名、brighter.lib になる
        { input, mul },      // 入力パラメータ、関数引数順になる
        "brighter"      // 関数名
    );    
}

実行するとbrighter.hとbrighter.libができているので、既存のプログラムにリンクして使うだけです。
入力、出力はHalideBuffer.h中のHalide::Runtime::Bufferを使えばOK。
Halide.dllは必要ありません。

use_staticlib.cpp
#include <HalideBuffer.h>
#include "brighter.h"

void Use_StaticLib()
{
    using namespace Halide;

    Runtime::Buffer<uint8_t> src(640, 480, 3);
    Runtime::Buffer<uint8_t> dst(640, 480, 3);

    /* 画像読み込みコードは省略 */

    brighter(src, 1.5f, dst);    // 出力は生成時のパラメータの最後につく
}

クロスコンパイル

compile_to_static_libraryには4番目の引数があり、OSやCPUアーキテクチャ、SIMDの有無などを設定できます。
指定しない場合は、AOTコンパイル時の環境が自動的に使用されます。

gen_staticlib.cpp
#include <Halide.h>

void Gen_StaticLib()
{
    using namespace Halide;

    ImageParam input(type_of<uint8_t>(), 3);

    Func brighter;
    Var x, y, ch;
    brighter(x, y, ch) = cast<uint8_t>(min(input(x, y, ch) * 1.5f, 255));
    brighter.parallel(y);

    // 動作環境の指定
    Target env;
    env.os = Target::OS::Windows;
    env.arch = Target::Arch::X86;
    env.bits = 64;
    env.set_feature(Target::Feature::AVX2);    // vectorizeしていないからあまり意味がないが…

    brighter.compile_to_static_library(
        "brighter", 
        { input }, 
        "brighter", 
        env          //ここに指定
    );    
}

生成した複数のスタティックライブラリをリンクするとき

1つの.libファイルに複数のFuncを含めることはできないようです。
処理ごとに.libも複数生成する必要があります。

gen_static_lib_multi1.cpp
#include <Halide.h>

void Gen_StaticLib()
{
    using namespace Halide;

    ImageParam input(type_of<uint8_t>(), 2);
    Param<float> val;

    Func mul, add;
    Var x, y;

    mul(x, y) = cast<uint8_t>(min(input(x, y) * val, 255));
    add(x, y) = cast<uint8_t>(min(input(x, y) + val, 255));    

    mul.compile_to_static_library(
        "mul",        // mul.lib
        { input, val },
        "mul"
    );

    add.compile_to_static_library(
        "add",        // add.lib
        { input, val },
        "add"
    );
}

が、これらの.libを同時に使おうとするとリンクエラーになってしまいます。
どうやら指定なしだと.libにはHalideのランタイム関数も同時に含まれるようで、ランタイムの重複定義でコケるっぽいです。

リンクする.libのうちどれか一つだけにランタイムを持たせるように、Targetを設定してやると解決。

gen_static_lib_multi1.cpp
#include <Halide.h>

void Gen_StaticLib()
{
    using namespace Halide;

   /* 略 */

    Target env, env_no_runtime;

    env.os = Target::OS::Windows;
    env.arch = Target::Arch::X86;
    env.bits = 64;
    env.set_feature(Target::Feature::AVX2);

    env_no_runtime  = env.with_feature(Target::Feature::NoRuntime);   // ランタイム生成を抑制

    mul.compile_to_static_library(
        "mul",        // mul.lib
        { input, val },
        "mul",
        env           // こちらにHalideランタイムが含まれる
    );

    add.compile_to_static_library(
        "add",        // add.lib
        { input, val },
        "add",
        env_no_runtime  //こちらはランタイムなし
    );
}

あるいは、ファイルが1つ増えますが、実際には呼びださない適当なFuncを作ってランタイムだけの.libを作るほうが管理が楽かもしれません。

gen_static_lib_multi2.cpp
#include <Halide.h>

using namespace Halide;

void Gen_Halide_Runtime(Target& env)
{
    // 実際には呼ばない関数
    Func f;
    Var x;

    f(x) = x;

    f.compile_to_static_library(
        "Halide_Runtime",
        {},
        "DoNotCall",
        env.without_feature(Target::Feature::NoRuntime)    // ここだけNoRuntimeを外す -> ランタイムあり
    );
}

void Gen_Mul(Target& env)
{
    ImageParam input(type_of<uint8_t>(), 2);
    Param<float> val;

    Func mul;
    Var x, y;

    mul(x, y) = cast<uint8_t>(min(input(x, y) * val, 255));

    mul.compile_to_static_library(
        "mul",        // mul.lib
        { input, val },
        "mul",
        env           
    );
}

void Gen_Add(Target& env)
{
    ImageParam input(type_of<uint8_t>(), 2);
    Param<float> val;

    Func add;
    Var x, y;

    add(x, y) = cast<uint8_t>(min(input(x, y) + val, 255));

    add.compile_to_static_library(
        "add",        // add.lib
        { input, val },
        "add",
        env           
    );
}

int main()
{
    Target env;
    env.os = Target::OS::Windows;
    env.arch = Target::Arch::X86;
    env.bits = 64;
    env.set_features(
     { Target::Feature::AVX2,
       Target::Feature::NoRuntime }  // 基本はNoRuntimeにしておく
    );

   Gen_Halide_Runtime(env);   // ランタイムあり
   Gen_Mul(env);              // ランタイムなし
   Gen_Add(env);              // ランタイムなし
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1