program.cpp 24 KB
Newer Older
Paul's avatar
Paul committed
1
2
3
#include <migraphx/program.hpp>
#include <migraphx/stringutils.hpp>
#include <migraphx/instruction.hpp>
4
#include <migraphx/op/identity.hpp>
Paul's avatar
Paul committed
5
#include <migraphx/target.hpp>
Paul's avatar
Paul committed
6
7
8
#include <migraphx/env.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/time.hpp>
9
#include <migraphx/pass_manager.hpp>
10
#include <migraphx/register_target.hpp>
Shucai Xiao's avatar
Shucai Xiao committed
11
#include <migraphx/iterator_for.hpp>
12
#include <migraphx/algorithm.hpp>
Shucai Xiao's avatar
Shucai Xiao committed
13
#include <migraphx/make_op.hpp>
Paul's avatar
Paul committed
14
#include <iostream>
Paul's avatar
Paul committed
15
#include <sstream>
Paul's avatar
Paul committed
16
#include <algorithm>
17
#include <set>
Paul's avatar
Paul committed
18
#include <utility>
19

20
#include <unordered_set>
Shucai Xiao's avatar
Shucai Xiao committed
21
22
#include <map>
#include <cassert>
Paul's avatar
Paul committed
23

Paul's avatar
Paul committed
24
namespace migraphx {
Paul's avatar
Paul committed
25
inline namespace MIGRAPHX_INLINE_NS {
Paul's avatar
Paul committed
26

Paul's avatar
Paul committed
27
28
struct program_impl
{
Shucai Xiao's avatar
Shucai Xiao committed
29
    // A map is used to keep references to modules of the program
30
    std::unordered_map<std::string, module> modules;
Paul's avatar
Paul committed
31
    context ctx;
32
    std::string target_name;
Paul's avatar
Paul committed
33
34
};

35
program::program() : impl(std::make_unique<program_impl>()) { this->create_module("main"); }
Paul's avatar
Paul committed
36

Paul's avatar
Paul committed
37
program::program(program&&) noexcept = default;
Shucai Xiao's avatar
Shucai Xiao committed
38
program::~program() noexcept         = default;
Paul's avatar
Paul committed
39

40
// copy constructor
Shucai Xiao's avatar
Shucai Xiao committed
41
program::program(const program& p) { assign(p); }
42
43

// copy assignment operator
Shucai Xiao's avatar
Shucai Xiao committed
44
program& program::operator=(program p)
45
{
Shucai Xiao's avatar
Shucai Xiao committed
46
    std::swap(p.impl, this->impl);
47
48
49
    return *this;
}

Shucai Xiao's avatar
Shucai Xiao committed
50
void program::assign(const program& p)
51
{
Shucai Xiao's avatar
Shucai Xiao committed
52
    if(!impl)
53
54
55
    {
        impl = std::make_unique<program_impl>();
    }
Shucai Xiao's avatar
Shucai Xiao committed
56
    else if(!impl->modules.empty())
57
    {
Shucai Xiao's avatar
Shucai Xiao committed
58
        impl->modules.clear();
59
    }
Shucai Xiao's avatar
Shucai Xiao committed
60

61
    impl->ctx         = p.impl->ctx;
Shucai Xiao's avatar
Shucai Xiao committed
62
63
    impl->target_name = p.impl->target_name;
    impl->modules     = p.impl->modules;
Shucai Xiao's avatar
Shucai Xiao committed
64
65
66
67

    // build a map from old ins to new ins
    // Build a map from old module to new module
    std::unordered_map<module_ref, module_ref> mod_map;
Paul's avatar
Paul committed
68
69
70
71
72
    std::transform(
        impl->modules.begin(),
        impl->modules.end(),
        std::inserter(mod_map, mod_map.begin()),
        [&](auto&& xp) { return std::make_pair(&p.impl->modules.at(xp.first), &xp.second); });
Shucai Xiao's avatar
Shucai Xiao committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

    std::unordered_map<instruction_ref, instruction_ref> ins_map;
    for(auto&& pp : mod_map)
    {
        auto old_ins = iterator_for(*pp.first);
        auto new_ins = iterator_for(*pp.second);
        std::transform(old_ins.begin(),
                       old_ins.end(),
                       new_ins.begin(),
                       std::inserter(ins_map, ins_map.begin()),
                       [](auto x, auto y) { return std::make_pair(x, y); });
    }

    // Update all references from all modules
    for(auto&& mp : impl->modules)
    {
89
        for(auto ins : iterator_for(mp.second))
Shucai Xiao's avatar
Shucai Xiao committed
90
91
            instruction::replace_refs(ins, ins_map, mod_map);
    }
92
93
}

Paul's avatar
Paul committed
94
shape program::get_parameter_shape(std::string name) const
Paul's avatar
Paul committed
95
{
Shucai Xiao's avatar
Shucai Xiao committed
96
97
    const auto* mm = this->get_main_module();
    return mm->get_parameter_shape(std::move(name));
Paul's avatar
Paul committed
98
99
}

100
101
std::vector<std::string> program::get_parameter_names() const
{
Shucai Xiao's avatar
Shucai Xiao committed
102
103
    const auto* mm = this->get_main_module();
    return mm->get_parameter_names();
104
105
}

mei-ye's avatar
mei-ye committed
106
107
instruction_ref program::get_parameter(std::string name) const
{
Shucai Xiao's avatar
Shucai Xiao committed
108
109
    const auto* mm = this->get_main_module();
    return mm->get_parameter(std::move(name));
mei-ye's avatar
mei-ye committed
110
111
}

Paul's avatar
Paul committed
112
113
std::unordered_map<std::string, shape> program::get_parameter_shapes() const
{
Shucai Xiao's avatar
Shucai Xiao committed
114
115
    const auto* mm = this->get_main_module();
    return mm->get_parameter_shapes();
Paul's avatar
Paul committed
116
117
}

Shucai Xiao's avatar
Shucai Xiao committed
118
std::size_t program::size() const { return impl->modules.size(); }
119

120
121
std::vector<shape> program::get_output_shapes() const
{
Shucai Xiao's avatar
Shucai Xiao committed
122
123
    const auto* mm = this->get_main_module();
    return mm->get_output_shapes();
124
}
Paul's avatar
Paul committed
125

Paul's avatar
Paul committed
126
127
context& program::get_context() const { return impl->ctx; }

Paul's avatar
Paul committed
128
129
instruction_ref program::validate() const
{
Shucai Xiao's avatar
Shucai Xiao committed
130
131
    const auto* mm = this->get_main_module();
    return mm->validate();
Paul's avatar
Paul committed
132
133
}

134
135
bool program::is_compiled() const { return not this->impl->target_name.empty(); }

136
void program::compile(const target& t, compile_options options)
Paul's avatar
Paul committed
137
{
138
139
140
    assert(not this->is_compiled());
    this->impl->target_name = t.name();
    this->impl->ctx         = t.get_context();
Paul's avatar
Paul committed
141
    if(enabled(MIGRAPHX_TRACE_COMPILE{}))
142
        options.trace = tracer{std::cout};
Shucai Xiao's avatar
Shucai Xiao committed
143

144
145
    options.trace(*this);
    options.trace();
Shucai Xiao's avatar
Shucai Xiao committed
146
147
148

    auto mods = this->get_modules();
    std::reverse(mods.begin(), mods.end());
Shucai Xiao's avatar
Shucai Xiao committed
149
150
    auto&& passes = t.get_passes(this->impl->ctx, options);

Shucai Xiao's avatar
Shucai Xiao committed
151
    for(const auto& mod : mods)
Paul's avatar
Paul committed
152
    {
Shucai Xiao's avatar
Shucai Xiao committed
153
154
155
156
157
158
159
160
        assert(mod->validate() == mod->end());
        run_passes(*mod, passes, options.trace);
        auto invalid = mod->validate();
        if(invalid != mod->end())
        {
            MIGRAPHX_THROW("Invalid module " + mod->name() + " from compilation at instruction " +
                           std::to_string(std::distance(mod->begin(), invalid)));
        }
161
162
163
164
165
166
167
        auto dangling = mod->find_dangling_reference();
        if(dangling != mod->end())
        {
            auto index = std::distance(mod->begin(), dangling);
            MIGRAPHX_THROW("Dangling reference in module " + mod->name() + " from instruction " +
                           std::to_string(index));
        }
Shucai Xiao's avatar
Shucai Xiao committed
168
        mod->finalize(this->impl->ctx);
Paul's avatar
Paul committed
169
    }
Paul's avatar
Paul committed
170
171
172
173
}

void program::finalize()
{
Shucai Xiao's avatar
Shucai Xiao committed
174
175
    auto* mm = this->get_main_module();
    mm->finalize(this->impl->ctx);
Paul's avatar
Paul committed
176
177
}

Paul's avatar
Paul committed
178
template <class F>
Shucai Xiao's avatar
Shucai Xiao committed
179
std::vector<argument> generic_eval(const module* mod,
180
181
                                   context& ctx,
                                   std::unordered_map<std::string, argument> params,
Shucai Xiao's avatar
Shucai Xiao committed
182
                                   std::unordered_map<instruction_ref, argument> results,
183
                                   F trace)
Paul's avatar
Paul committed
184
{
Shucai Xiao's avatar
Shucai Xiao committed
185
186
    assert(mod->validate() == mod->end());
    results.reserve(mod->size() * 2);
Paul's avatar
Paul committed
187
188
    std::vector<argument> values;
    values.reserve(16);
Shucai Xiao's avatar
Shucai Xiao committed
189
    for(auto ins : iterator_for(*mod))
Paul's avatar
Paul committed
190
    {
191
192
        const auto& name = ins->name();
        if(name == "@literal")
Paul's avatar
Paul committed
193
        {
Paul's avatar
Paul committed
194
            results.emplace(ins, trace(ins, [&] { return ins->get_literal().get_argument(); }));
Paul's avatar
Paul committed
195
        }
196
        else if(name == "@param")
Paul's avatar
Paul committed
197
        {
Paul's avatar
Paul committed
198
199
200
201
202
            results.emplace(
                ins, trace(ins, [&] {
                    auto param_name = any_cast<builtin::param>(ins->get_operator()).parameter;
                    if(not contains(params, param_name))
                        MIGRAPHX_THROW("Parameter not found: " + param_name);
203
                    auto param = params[param_name];
Paul's avatar
Paul committed
204
205
206
207
208
                    if(param.get_shape() != ins->get_shape())
                        MIGRAPHX_THROW("Incorrect shape {" + to_string(param.get_shape()) +
                                       "} for parameter: " + param_name);
                    return param;
                }));
Paul's avatar
Paul committed
209
        }
210
        else if(name == "@outline")
Paul's avatar
Paul committed
211
        {
Paul's avatar
Paul committed
212
            results.emplace(ins, trace(ins, [&] { return argument{ins->get_shape(), nullptr}; }));
Paul's avatar
Paul committed
213
        }
214
215
216
217
218
219
220
221
222
223
224
225
226
        else if(name == "@return")
        {
            std::vector<argument> prog_outputs;
            std::transform(ins->inputs().begin(),
                           ins->inputs().end(),
                           std::back_inserter(prog_outputs),
                           [&](instruction_ref i) {
                               assert(results.find(i) != results.end());
                               return results[i];
                           });

            return prog_outputs;
        }
Paul's avatar
Paul committed
227
228
        else
        {
Paul's avatar
Paul committed
229
            values.resize(ins->inputs().size());
Paul's avatar
Paul committed
230
231
232
233
234
            std::transform(
                ins->inputs().begin(), ins->inputs().end(), values.begin(), [&](instruction_ref i) {
                    assert(results.find(i) != results.end());
                    return results[i];
                });
Shucai Xiao's avatar
Shucai Xiao committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

            const auto& mod_args = ins->module_inputs();
            auto module_eval     = [&](module_ref smod,
                                   const std::unordered_map<std::string, argument>& inputs) {
                return generic_eval(smod, ctx, inputs, results, trace);
            };

            if(not mod_args.empty())
            {
                results.emplace(ins, trace(ins, [&] {
                                    return ins->normalized_operator().compute(
                                        values, mod_args, module_eval);
                                }));
            }
            else
            {
                results.emplace(ins, trace(ins, [&] {
                                    return ins->normalized_operator().compute(
                                        ctx, ins->get_shape(), values);
                                }));
            }
Paul's avatar
Paul committed
256
        }
257
        assert(results.find(ins) != results.end());
Paul's avatar
Paul committed
258
    }
Shucai Xiao's avatar
Shucai Xiao committed
259
    return {results.at(std::prev(mod->end()))};
Paul's avatar
Paul committed
260
261
}

Shucai Xiao's avatar
Shucai Xiao committed
262
263
264
265
266
267
template <class F>
std::vector<argument> generic_eval(const program& p,
                                   context& ctx,
                                   std::unordered_map<std::string, argument> params,
                                   F trace)
{
Shucai Xiao's avatar
Shucai Xiao committed
268
269
    const module* mm = p.get_main_module();
    return generic_eval(mm, ctx, params, {}, trace);
Shucai Xiao's avatar
Shucai Xiao committed
270
271
}

272
std::vector<argument> program::eval(parameter_map params) const
Paul's avatar
Paul committed
273
{
Paul's avatar
Paul committed
274
275
    auto& ctx = this->impl->ctx;
#ifndef NDEBUG
Paul's avatar
Paul committed
276
    auto sctx          = ctx;
Paul's avatar
Paul committed
277
278
279
    auto check_context = [&](auto f) {
        assert(is_shared(ctx, sctx));
        auto x = f();
Paul's avatar
Paul committed
280
        sctx   = ctx;
Paul's avatar
Paul committed
281
282
283
        return x;
    };
#else
Paul's avatar
Paul committed
284
    auto check_context = [](auto f) { return f(); };
Paul's avatar
Paul committed
285
#endif
Paul's avatar
Paul committed
286
287
288
289

    auto trace_level = value_of(MIGRAPHX_TRACE_EVAL{});

    if(trace_level > 0)
Paul's avatar
Paul committed
290
    {
Paul's avatar
Paul committed
291
        return generic_eval(*this, ctx, std::move(params), [&](auto& ins, auto f) {
Paul's avatar
Paul committed
292
            ctx.finish();
Paul's avatar
Paul committed
293
294
            std::cout << "Run instruction: ";
            this->debug_print(ins);
Paul's avatar
Paul committed
295
296
            auto result = check_context(f);
            ctx.finish();
Paul's avatar
Paul committed
297
            if(trace_level > 1 and ins->name().front() != '@' and ins->name() != "load")
Paul's avatar
Paul committed
298
299
                std::cout << "Ouput: " << result << std::endl;
            return result;
Paul's avatar
Paul committed
300
        });
Paul's avatar
Paul committed
301
302
303
304
    }
    else
    {
        return generic_eval(
Paul's avatar
Paul committed
305
            *this, ctx, std::move(params), [&](auto&, auto f) { return check_context(f); });
Paul's avatar
Paul committed
306
    }
Paul's avatar
Paul committed
307
308
}

309
const int program_file_version = 4;
310
311
312
313
314
315
316
317

value program::to_value() const
{
    value result;
    result["version"] = program_file_version;
    result["target"]  = this->impl->target_name;
    if(not this->impl->target_name.empty())
        result["context"] = this->impl->ctx.to_value();
Shucai Xiao's avatar
Shucai Xiao committed
318

319
    value module_vals = value::object{};
Shucai Xiao's avatar
Shucai Xiao committed
320
    std::unordered_map<instruction_ref, std::string> names;
321
    for(auto& mod : this->get_modules())
Shucai Xiao's avatar
Shucai Xiao committed
322
    {
Shucai Xiao's avatar
Shucai Xiao committed
323
324
        value mod_val;
        value nodes;
325
326
        mod_val["name"] = mod->name();
        names           = mod->print(
Shucai Xiao's avatar
Shucai Xiao committed
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
            [&](auto ins, auto ins_names) {
                value node;
                node["output"]     = ins_names.at(ins);
                node["name"]       = ins->name();
                node["shape"]      = migraphx::to_value(ins->get_shape());
                node["normalized"] = ins->is_normalized();
                if(ins->name() == "@literal")
                    node["literal"] = migraphx::to_value(ins->get_literal());
                node["operator"] = ins->get_operator().to_value();
                std::vector<std::string> inputs;
                std::transform(ins->inputs().begin(),
                               ins->inputs().end(),
                               std::back_inserter(inputs),
                               [&](auto i) {
                                   assert(contains(ins_names, i));
                                   return ins_names.at(i);
                               });
                node["inputs"]   = inputs;
                auto module_args = ins->module_inputs();
                if(not module_args.empty())
                {
                    std::vector<std::string> module_inputs;
                    std::transform(module_args.begin(),
                                   module_args.end(),
                                   std::back_inserter(module_inputs),
                                   [&](auto mod_ref) { return mod_ref->name(); });
                    node["module_inputs"] = module_inputs;
                }

                nodes.push_back(node);
            },
            names);
        mod_val["nodes"] = nodes;

361
        module_vals[mod->name()] = mod_val;
Shucai Xiao's avatar
Shucai Xiao committed
362
    }
Shucai Xiao's avatar
Shucai Xiao committed
363
364
365

    result["modules"] = module_vals;

366
367
    return result;
}
Shucai Xiao's avatar
Shucai Xiao committed
368

Shucai Xiao's avatar
Shucai Xiao committed
369
370
371
372
373
static void mod_from_val(module_ref mod,
                         const value& v,
                         std::unordered_map<std::string, instruction_ref>& instructions,
                         const std::unordered_map<std::string, module_ref>& map_mods)
{
374
    const auto& module_val = v.at(mod->name());
Shucai Xiao's avatar
Shucai Xiao committed
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
    for(const value& node : module_val.at("nodes"))
    {
        instruction_ref output;
        auto name       = node.at("name").to<std::string>();
        auto fields     = node.at("operator");
        auto normalized = node.at("normalized").to<bool>();

        if(name == "@param")
        {
            output = mod->add_parameter(fields["parameter"].to<std::string>(),
                                        migraphx::from_value<shape>(node.at("shape")));
        }
        else if(name == "@literal")
        {
            output = mod->add_literal(migraphx::from_value<literal>(node.at("literal")));
        }
        else
        {
            auto op = make_op(name, fields);
            std::vector<instruction_ref> inputs;
            std::transform(node.at("inputs").begin(),
                           node.at("inputs").end(),
                           std::back_inserter(inputs),
                           [&](const value& i) {
                               auto i_name = i.to<std::string>();
                               assert(contains(instructions, i_name));
                               return instructions.at(i_name);
                           });

            std::vector<module_ref> module_inputs;
            if(node.contains("module_inputs"))
            {
                std::transform(node.at("module_inputs").begin(),
                               node.at("module_inputs").end(),
                               std::back_inserter(module_inputs),
                               [&](const value& i) { return map_mods.at(i.to<std::string>()); });

                for(auto& smod : module_inputs)
                {
                    mod_from_val(smod, v, instructions, map_mods);
                }
            }

            if(name == "@return")
            {
                output = mod->add_return(inputs);
            }
            else if(module_inputs.empty())
            {
                output = mod->add_instruction(op, inputs);
            }
            else
            {
                output = mod->add_instruction(op, inputs, module_inputs);
            }
        }
        output->set_normalized(normalized);
        instructions[node.at("output").to<std::string>()] = output;
    }
}

436
437
438
439
void program::from_value(const value& v)
{
    auto version = v.at("version").to<int>();
    if(version != program_file_version)
Shucai Xiao's avatar
Shucai Xiao committed
440
441
442
443
    {
        MIGRAPHX_THROW("Warning: Program version mismatch");
    }

444
445
446
447
448
449
450
451
    this->impl->target_name = v.at("target").to<std::string>();
    if(not this->impl->target_name.empty())
    {
        target t        = make_target(this->impl->target_name);
        this->impl->ctx = t.get_context();
        this->impl->ctx.from_value(v.at("context"));
    }

Shucai Xiao's avatar
Shucai Xiao committed
452
453
    auto module_vals = v.at("modules");
    for(const auto& vv : module_vals)
454
    {
455
        const auto& name = vv.get_key();
Shucai Xiao's avatar
Shucai Xiao committed
456
457
        if(name == "main")
            continue;
458
        impl->modules.emplace(name, name);
459
    }
460
    std::unordered_map<std::string, module_ref> map_mods;
Paul's avatar
Paul committed
461
462
463
464
    std::transform(impl->modules.begin(),
                   impl->modules.end(),
                   std::inserter(map_mods, map_mods.end()),
                   [&](auto&& pp) { return std::make_pair(pp.first, &pp.second); });
Shucai Xiao's avatar
Shucai Xiao committed
465
466
467
468
469

    std::unordered_map<std::string, instruction_ref> map_insts;
    auto* mm = get_main_module();
    mod_from_val(mm, module_vals, map_insts, map_mods);

470
471
472
    this->finalize();
}

Paul's avatar
Paul committed
473
474
475
double common_average(const std::vector<double>& v)
{
    std::size_t n = v.size() / 4;
Paul's avatar
Paul committed
476
477
    double total  = std::accumulate(v.begin() + n, v.end() - n, 0.0);
    return total / std::distance(v.begin() + n, v.end() - n);
Paul's avatar
Paul committed
478
479
}

Paul's avatar
Paul committed
480
481
482
void program::perf_report(std::ostream& os, std::size_t n, parameter_map params) const
{
    using milliseconds = std::chrono::duration<double, std::milli>;
Paul's avatar
Paul committed
483
    auto& ctx          = this->impl->ctx;
Paul's avatar
Paul committed
484
485
    // Run once by itself
    eval(params);
Paul's avatar
Paul committed
486
    ctx.finish();
Paul's avatar
Paul committed
487
    // Run and time entire program
Paul's avatar
Paul committed
488
489
    std::vector<double> total_vec;
    total_vec.reserve(n);
Paul's avatar
Paul committed
490
    for(std::size_t i = 0; i < n; i++)
Paul's avatar
Paul committed
491
    {
Paul's avatar
Paul committed
492
493
494
495
        total_vec.push_back(time<milliseconds>([&] {
            eval(params);
            ctx.finish();
        }));
Paul's avatar
Paul committed
496
    }
Paul's avatar
Paul committed
497
498
    std::sort(total_vec.begin(), total_vec.end());
    std::unordered_map<instruction_ref, std::vector<double>> ins_vec;
Paul's avatar
Paul committed
499
    // Fill the map
Paul's avatar
Paul committed
500
    generic_eval(*this, ctx, params, [&](auto ins, auto) {
Paul's avatar
Paul committed
501
        ins_vec[ins].reserve(n);
Paul's avatar
Paul committed
502
503
        return argument{};
    });
Paul's avatar
Paul committed
504
    // Run and time each instruction
Paul's avatar
Paul committed
505
    for(std::size_t i = 0; i < n; i++)
Paul's avatar
Paul committed
506
    {
Paul's avatar
Paul committed
507
        generic_eval(*this, ctx, params, [&](auto ins, auto f) {
508
            argument result;
Paul's avatar
Paul committed
509
510
511
512
            ins_vec[ins].push_back(time<milliseconds>([&] {
                result = f();
                ctx.finish();
            }));
513
            return result;
Paul's avatar
Paul committed
514
515
        });
    }
Paul's avatar
Paul committed
516
517
    for(auto&& p : ins_vec)
        std::sort(p.second.begin(), p.second.end());
Paul's avatar
Paul committed
518
    // Run and time implicit overhead
Paul's avatar
Paul committed
519
520
    std::vector<double> overhead_vec;
    overhead_vec.reserve(n);
Paul's avatar
Paul committed
521
    for(std::size_t i = 0; i < n; i++)
Paul's avatar
Paul committed
522
    {
Paul's avatar
Paul committed
523
        overhead_vec.push_back(time<milliseconds>([&] { dry_run(params); }));
Paul's avatar
Paul committed
524
525
    }

Paul's avatar
Paul committed
526
    double total_time             = common_average(total_vec);
Paul's avatar
Paul committed
527
    double rate                   = 1000.0 / total_time;
Paul's avatar
Paul committed
528
    double overhead_time          = common_average(overhead_vec);
Paul's avatar
Paul committed
529
    double overhead_percent       = overhead_time * 100.0 / total_time;
Paul's avatar
Paul committed
530
    double total_instruction_time = 0.0;
Paul's avatar
Paul committed
531
    std::unordered_map<std::string, double> op_times;
Paul's avatar
Paul committed
532
    for(auto&& p : ins_vec)
Paul's avatar
Paul committed
533
534
    {
        double avg = common_average(p.second);
Paul's avatar
Paul committed
535
        op_times[p.first->name()] += avg;
Paul's avatar
Paul committed
536
537
        total_instruction_time += avg;
    }
Paul's avatar
Paul committed
538
539
    double calculate_overhead_time    = total_time - total_instruction_time;
    double calculate_overhead_percent = calculate_overhead_time * 100.0 / total_time;
Paul's avatar
Paul committed
540

Shucai Xiao's avatar
Shucai Xiao committed
541
542
543
    std::unordered_map<instruction_ref, std::string> names;
    this->print(names, [&](auto ins, auto ins_names) {
        instruction::print(std::cout, ins, ins_names);
544
545
546
547
548

        // skip return instruction
        if(ins->name() == "@return")
            return;

Paul's avatar
Paul committed
549
550
551
        double avg     = common_average(ins_vec[ins]);
        double percent = std::ceil(100.0 * avg / total_instruction_time);
        os << ": " << avg << "ms, " << percent << "%";
552
        os << std::endl;
Paul's avatar
Paul committed
553
    });
Paul's avatar
Paul committed
554
555
556

    os << std::endl;
    os << "Summary:" << std::endl;
557
558
559
560
561
562
563
    std::vector<std::pair<double, std::string>> op_times_sorted;
    std::transform(op_times.begin(),
                   op_times.end(),
                   std::back_inserter(op_times_sorted),
                   [](auto p) { return std::make_pair(p.second, p.first); });
    std::sort(op_times_sorted.begin(), op_times_sorted.end(), std::greater<>{});
    for(auto&& p : op_times_sorted)
Paul's avatar
Paul committed
564
    {
565
566
        auto&& name    = p.second;
        double avg     = p.first;
Paul's avatar
Paul committed
567
568
569
570
571
        double percent = std::ceil(100.0 * avg / total_instruction_time);
        os << name << ": " << avg << "ms, " << percent << "%" << std::endl;
    }

    os << std::endl;
Paul's avatar
Paul committed
572

Paul's avatar
Paul committed
573
    os << "Rate: " << rate << "/sec" << std::endl;
Paul's avatar
Paul committed
574
575
    os << "Total time: " << total_time << "ms" << std::endl;
    os << "Total instructions time: " << total_instruction_time << "ms" << std::endl;
Paul's avatar
Paul committed
576
577
578
579
    os << "Overhead time: " << overhead_time << "ms"
       << ", " << calculate_overhead_time << "ms" << std::endl;
    os << "Overhead: " << std::round(overhead_percent) << "%"
       << ", " << std::round(calculate_overhead_percent) << "%" << std::endl;
Paul's avatar
Paul committed
580
581
}

Paul's avatar
Paul committed
582
583
void program::debug_print() const { std::cout << *this << std::endl; }
void program::debug_print(instruction_ref ins) const
Paul's avatar
Paul committed
584
{
Shucai Xiao's avatar
Shucai Xiao committed
585
    std::unordered_map<instruction_ref, std::string> names;
586
587
    if(std::any_of(this->impl->modules.begin(), this->impl->modules.end(), [&](const auto& pp) {
           return (pp.second.end() == ins);
Shucai Xiao's avatar
Shucai Xiao committed
588
       }))
Paul's avatar
Paul committed
589
590
591
592
    {
        std::cout << "End instruction" << std::endl;
        return;
    }
593
594
    else if(std::none_of(this->impl->modules.begin(),
                         this->impl->modules.end(),
595
                         [&](const auto& pp) { return pp.second.has_instruction(ins); }))
Paul's avatar
Paul committed
596
597
598
599
    {
        std::cout << "Instruction not part of program" << std::endl;
        return;
    }
Shucai Xiao's avatar
Shucai Xiao committed
600

Paul's avatar
Paul committed
601
    std::stringstream ss;
Shucai Xiao's avatar
Shucai Xiao committed
602
    this->print(names, [&](auto x, auto ins_names) {
Paul's avatar
Paul committed
603
        if(x == ins)
Paul's avatar
Paul committed
604
        {
Shucai Xiao's avatar
Shucai Xiao committed
605
            instruction::print(std::cout, x, ins_names);
Paul's avatar
Paul committed
606
607
608
609
610
            std::cout << std::endl;
        }
    });
}

Shucai Xiao's avatar
Shucai Xiao committed
611
612
613
614
void program::print(
    std::unordered_map<instruction_ref, std::string>& names,
    const std::function<void(instruction_ref, std::unordered_map<instruction_ref, std::string>)>&
        print_func) const
615
{
616
    for(const auto& pp : this->impl->modules)
617
    {
618
        names = pp.second.print(print_func, names);
619
620
621
    }
}

Shucai Xiao's avatar
Shucai Xiao committed
622
void program::print_graph(std::ostream& os, bool brief) const
623
{
Shucai Xiao's avatar
Shucai Xiao committed
624
625
    const auto* mm = this->get_main_module();
    mm->print_graph(os, brief);
626
627
628
629
}

void program::print_cpp(std::ostream& os) const
{
Shucai Xiao's avatar
Shucai Xiao committed
630
631
632
633
634
635
636
637
    auto vec_modules = this->get_modules();
    std::unordered_map<instruction_ref, std::string> names;
    for(auto& mod : vec_modules)
    {
        os << "module: \"" << mod->name() << "\"" << std::endl;
        names = mod->print_cpp(os, names);
        os << std::endl;
    }
638
639
}

Paul's avatar
Paul committed
640
641
void program::dry_run(std::unordered_map<std::string, argument> params) const
{
Paul's avatar
Paul committed
642
    auto& ctx = this->impl->ctx;
Paul's avatar
Paul committed
643
    generic_eval(*this, ctx, std::move(params), [](auto&&...) { return argument{}; });
Paul's avatar
Paul committed
644
645
}

Shucai Xiao's avatar
Shucai Xiao committed
646
void program::annotate(std::ostream& os, const std::function<void(instruction_ref)>& a) const
Paul's avatar
Paul committed
647
{
648
    for(auto& pp : this->impl->modules)
Shucai Xiao's avatar
Shucai Xiao committed
649
    {
650
651
        std::cout << pp.first << ":" << std::endl;
        pp.second.annotate(os, a);
Shucai Xiao's avatar
Shucai Xiao committed
652
    }
Paul's avatar
Paul committed
653
654
}

Paul's avatar
Paul committed
655
const module* program::get_module(const std::string& name) const { return &impl->modules.at(name); }
Shucai Xiao's avatar
Shucai Xiao committed
656
657
658

module* program::create_module(const std::string& name)
{
659
660
    auto r = impl->modules.emplace(name, name);
    return &(r.first->second);
Shucai Xiao's avatar
Shucai Xiao committed
661
662
}

Paul's avatar
Paul committed
663
module* program::get_module(const std::string& name) { return &impl->modules.at(name); }
Shucai Xiao's avatar
Shucai Xiao committed
664
665
666
667
668

module* program::get_main_module() { return get_module("main"); }

const module* program::get_main_module() const { return get_module("main"); }

Paul's avatar
Paul committed
669
template <class T>
670
std::vector<T*> generic_get_modules(T* mm)
Shucai Xiao's avatar
Shucai Xiao committed
671
{
672
    std::vector<T*> vec_modules;
Shucai Xiao's avatar
Shucai Xiao committed
673
674
675
676
677
    vec_modules.push_back(mm);
    auto sub_modules = mm->get_sub_modules();
    vec_modules.insert(vec_modules.end(), sub_modules.begin(), sub_modules.end());
    return vec_modules;
}
Shucai Xiao's avatar
Shucai Xiao committed
678

Paul's avatar
Paul committed
679
template <class Map, class T, class OutputIterator>
680
void generic_get_unused_modules(Map& m, const std::vector<T*>& mods, OutputIterator out)
Shucai Xiao's avatar
Shucai Xiao committed
681
{
682
683
684
685
    std::unordered_set<std::string> used;
    std::transform(mods.begin(), mods.end(), std::inserter(used, used.end()), [](auto&& mod) {
        return mod->name();
    });
Paul's avatar
Paul committed
686
687
688
689
690
    transform_if(m.begin(),
                 m.end(),
                 out,
                 [&](auto&& pp) { return not contains(used, pp.first); },
                 [](auto&& pp) { return &pp.second; });
691
}
Shucai Xiao's avatar
Shucai Xiao committed
692

693
694
695
696
697
698
699
700
701
702
703
704
std::vector<const module*> program::get_modules() const
{
    auto result = generic_get_modules(this->get_main_module());
    generic_get_unused_modules(impl->modules, result, std::back_inserter(result));
    return result;
}

std::vector<module*> program::get_modules()
{
    auto result = generic_get_modules(this->get_main_module());
    generic_get_unused_modules(impl->modules, result, std::back_inserter(result));
    return result;
Shucai Xiao's avatar
Shucai Xiao committed
705
706
}

707
708
program& program::sort()
{
709
    for(auto& pp : this->impl->modules)
Shucai Xiao's avatar
Shucai Xiao committed
710
    {
711
        pp.second.sort();
Shucai Xiao's avatar
Shucai Xiao committed
712
713
    }

714
715
716
    return *this;
}

Paul's avatar
Paul committed
717
bool operator==(const program& x, const program& y) { return to_string(x) == to_string(y); }
Paul's avatar
Paul committed
718

Paul's avatar
Paul committed
719
std::ostream& operator<<(std::ostream& os, const program& p)
Paul's avatar
Paul committed
720
{
Shucai Xiao's avatar
Shucai Xiao committed
721
722
723
    auto vec_modules = p.get_modules();
    std::unordered_map<instruction_ref, std::string> names;
    for(auto& mod : vec_modules)
Shucai Xiao's avatar
Shucai Xiao committed
724
    {
Shucai Xiao's avatar
Shucai Xiao committed
725
726
727
728
729
730
731
        os << "module: \"" << mod->name() << "\"" << std::endl;
        names = mod->print(
            [&](auto ins, auto ins_names) {
                instruction::print(os, ins, ins_names);
                os << std::endl;
            },
            names);
732
        os << std::endl;
Shucai Xiao's avatar
Shucai Xiao committed
733
734
    }

Paul's avatar
Paul committed
735
    return os;
Paul's avatar
Paul committed
736
}
Paul's avatar
Paul committed
737

Paul's avatar
Paul committed
738
} // namespace MIGRAPHX_INLINE_NS
Paul's avatar
Paul committed
739
} // namespace migraphx