program.cpp 23.9 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
68
69
70

    // 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;
    std::transform(impl->modules.begin(),
                   impl->modules.end(),
                   std::inserter(mod_map, mod_map.begin()),
71
                   [&](auto&& xp) { return std::make_pair(&p.impl->modules.at(xp.first), &xp.second); });
Shucai Xiao's avatar
Shucai Xiao committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

    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)
    {
88
        for(auto ins : iterator_for(mp.second))
Shucai Xiao's avatar
Shucai Xiao committed
89
90
            instruction::replace_refs(ins, ins_map, mod_map);
    }
91
92
}

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

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

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

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

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

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

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

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

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

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

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

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

Shucai Xiao's avatar
Shucai Xiao committed
150
    for(const auto& mod : mods)
Paul's avatar
Paul committed
151
    {
Shucai Xiao's avatar
Shucai Xiao committed
152
153
154
155
156
157
158
159
        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)));
        }
160
161
162
163
164
165
166
        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
167
        mod->finalize(this->impl->ctx);
Paul's avatar
Paul committed
168
    }
Paul's avatar
Paul committed
169
170
171
172
}

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

Paul's avatar
Paul committed
177
template <class F>
Shucai Xiao's avatar
Shucai Xiao committed
178
std::vector<argument> generic_eval(const module* mod,
179
180
                                   context& ctx,
                                   std::unordered_map<std::string, argument> params,
Shucai Xiao's avatar
Shucai Xiao committed
181
                                   std::unordered_map<instruction_ref, argument> results,
182
                                   F trace)
Paul's avatar
Paul committed
183
{
Shucai Xiao's avatar
Shucai Xiao committed
184
185
    assert(mod->validate() == mod->end());
    results.reserve(mod->size() * 2);
Paul's avatar
Paul committed
186
187
    std::vector<argument> values;
    values.reserve(16);
Shucai Xiao's avatar
Shucai Xiao committed
188
    for(auto ins : iterator_for(*mod))
Paul's avatar
Paul committed
189
    {
190
191
        const auto& name = ins->name();
        if(name == "@literal")
Paul's avatar
Paul committed
192
        {
Paul's avatar
Paul committed
193
            results.emplace(ins, trace(ins, [&] { return ins->get_literal().get_argument(); }));
Paul's avatar
Paul committed
194
        }
195
        else if(name == "@param")
Paul's avatar
Paul committed
196
        {
Paul's avatar
Paul committed
197
198
199
200
201
            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);
202
                    auto param = params[param_name];
Paul's avatar
Paul committed
203
204
205
206
207
                    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
208
        }
209
        else if(name == "@outline")
Paul's avatar
Paul committed
210
        {
Paul's avatar
Paul committed
211
            results.emplace(ins, trace(ins, [&] { return argument{ins->get_shape(), nullptr}; }));
Paul's avatar
Paul committed
212
        }
213
214
215
216
217
218
219
220
221
222
223
224
225
        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
226
227
        else
        {
Paul's avatar
Paul committed
228
            values.resize(ins->inputs().size());
Paul's avatar
Paul committed
229
230
231
232
233
            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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

            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
255
        }
256
        assert(results.find(ins) != results.end());
Paul's avatar
Paul committed
257
    }
Shucai Xiao's avatar
Shucai Xiao committed
258
    return {results.at(std::prev(mod->end()))};
Paul's avatar
Paul committed
259
260
}

Shucai Xiao's avatar
Shucai Xiao committed
261
262
263
264
265
266
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
267
268
    const module* mm = p.get_main_module();
    return generic_eval(mm, ctx, params, {}, trace);
Shucai Xiao's avatar
Shucai Xiao committed
269
270
}

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

    auto trace_level = value_of(MIGRAPHX_TRACE_EVAL{});

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

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

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
317

318
    value module_vals = value::object{};
Shucai Xiao's avatar
Shucai Xiao committed
319
    std::unordered_map<instruction_ref, std::string> names;
320
    for(auto& mod : this->get_modules())
Shucai Xiao's avatar
Shucai Xiao committed
321
    {
Shucai Xiao's avatar
Shucai Xiao committed
322
323
        value mod_val;
        value nodes;
324
325
        mod_val["name"] = mod->name();
        names           = mod->print(
Shucai Xiao's avatar
Shucai Xiao committed
326
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
            [&](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;

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

    result["modules"] = module_vals;

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

Shucai Xiao's avatar
Shucai Xiao committed
368
369
370
371
372
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)
{
373
    const auto& module_val = v.at(mod->name());
Shucai Xiao's avatar
Shucai Xiao committed
374
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
    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;
    }
}

435
436
437
438
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
439
440
441
442
    {
        MIGRAPHX_THROW("Warning: Program version mismatch");
    }

443
444
445
446
447
448
449
450
    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
451
452
    auto module_vals = v.at("modules");
    for(const auto& vv : module_vals)
453
    {
454
        const auto& name = vv.get_key();
Shucai Xiao's avatar
Shucai Xiao committed
455
456
        if(name == "main")
            continue;
457
        impl->modules.emplace(name, name);
458
    }
459
460
461
462
    std::unordered_map<std::string, module_ref> map_mods;
    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
463
464
465
466
467

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

468
469
470
    this->finalize();
}

Paul's avatar
Paul committed
471
472
473
double common_average(const std::vector<double>& v)
{
    std::size_t n = v.size() / 4;
Paul's avatar
Paul committed
474
475
    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
476
477
}

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

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

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

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

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

    os << std::endl;
    os << "Summary:" << std::endl;
555
556
557
558
559
560
561
    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
562
    {
563
564
        auto&& name    = p.second;
        double avg     = p.first;
Paul's avatar
Paul committed
565
566
567
568
569
        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
570

Paul's avatar
Paul committed
571
    os << "Rate: " << rate << "/sec" << std::endl;
Paul's avatar
Paul committed
572
573
    os << "Total time: " << total_time << "ms" << std::endl;
    os << "Total instructions time: " << total_instruction_time << "ms" << std::endl;
Paul's avatar
Paul committed
574
575
576
577
    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
578
579
}

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

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

Shucai Xiao's avatar
Shucai Xiao committed
609
610
611
612
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
613
{
614
    for(const auto& pp : this->impl->modules)
615
    {
616
        names = pp.second.print(print_func, names);
617
618
619
    }
}

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

void program::print_cpp(std::ostream& os) const
{
Shucai Xiao's avatar
Shucai Xiao committed
628
629
630
631
632
633
634
635
    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;
    }
636
637
}

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

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

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

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

module* program::get_module(const std::string& name)
{
666
    return &impl->modules.at(name);
Shucai Xiao's avatar
Shucai Xiao committed
667
668
669
670
671
672
}

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

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

673
674
template<class T>
std::vector<T*> generic_get_modules(T* mm)
Shucai Xiao's avatar
Shucai Xiao committed
675
{
676
    std::vector<T*> vec_modules;
Shucai Xiao's avatar
Shucai Xiao committed
677
678
679
680
681
    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
682

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