program.cpp 23.4 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>
Shucai Xiao's avatar
Shucai Xiao committed
12
#include <migraphx/make_op.hpp>
Paul's avatar
Paul committed
13
#include <iostream>
Paul's avatar
Paul committed
14
#include <sstream>
Paul's avatar
Paul committed
15
#include <algorithm>
16
#include <set>
Paul's avatar
Paul committed
17
#include <utility>
18

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

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

Paul's avatar
Paul committed
26
27
struct program_impl
{
Shucai Xiao's avatar
Shucai Xiao committed
28
    // A map is used to keep references to modules of the program
Shucai Xiao's avatar
Shucai Xiao committed
29
30
    // all the modules are store in the depth-first order
    std::list<module> modules;
Paul's avatar
Paul committed
31
    context ctx;
32
    std::string target_name;
Paul's avatar
Paul committed
33
34
};

Shucai Xiao's avatar
Shucai Xiao committed
35
program::program() : impl(std::make_unique<program_impl>()) { impl->modules.push_back({"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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

    // 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(),
                   p.impl->modules.begin(),
                   std::inserter(mod_map, mod_map.begin()),
                   [](auto&& x, auto&& y) { return std::make_pair(&y, &x); });

    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)
    {
        for(auto ins : iterator_for(mp))
            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
161
        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)));
        }
        mod->finalize(this->impl->ctx);
Paul's avatar
Paul committed
162
    }
Paul's avatar
Paul committed
163
164
165
166
}

void program::finalize()
{
Shucai Xiao's avatar
Shucai Xiao committed
167
168
    auto* mm = this->get_main_module();
    mm->finalize(this->impl->ctx);
Paul's avatar
Paul committed
169
170
}

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

            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
249
        }
250
        assert(results.find(ins) != results.end());
Paul's avatar
Paul committed
251
    }
252

Shucai Xiao's avatar
Shucai Xiao committed
253
    return {results.at(std::prev(mod->end()))};
Paul's avatar
Paul committed
254
255
}

Shucai Xiao's avatar
Shucai Xiao committed
256
257
258
259
260
261
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
262
263
    const module* mm = p.get_main_module();
    return generic_eval(mm, ctx, params, {}, trace);
Shucai Xiao's avatar
Shucai Xiao committed
264
265
}

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

    auto trace_level = value_of(MIGRAPHX_TRACE_EVAL{});

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

303
const int program_file_version = 4;
304
305
306
307
308
309
310
311

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
312

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

        module_vals.push_back(mod_val);
Shucai Xiao's avatar
Shucai Xiao committed
356
    }
Shucai Xiao's avatar
Shucai Xiao committed
357
358
359

    result["modules"] = module_vals;

360
361
    return result;
}
Shucai Xiao's avatar
Shucai Xiao committed
362

Shucai Xiao's avatar
Shucai Xiao committed
363
364
365
366
367
368
369
370
371
372
373
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
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)
{
    const auto* it = std::find_if(v.begin(), v.end(), [&](auto& mv) {
        return mv.at("name").template to<std::string>() == mod->name();
    });
    assert(it != v.end());

    const auto& module_val = *it;
    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
453
    auto module_vals = v.at("modules");
    std::unordered_map<std::string, module_ref> map_mods;
    for(const auto& vv : module_vals)
454
    {
Shucai Xiao's avatar
Shucai Xiao committed
455
456
457
458
459
        const auto& name = vv.at("name").to<std::string>();
        if(name == "main")
            continue;
        impl->modules.push_back({name});
        map_mods[name] = &impl->modules.back();
460
    }
Shucai Xiao's avatar
Shucai Xiao committed
461
462
463
464
465

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

466
467
468
    this->finalize();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Shucai Xiao's avatar
Shucai Xiao committed
651
652
653
654
655
656
657
658
const module* program::get_module(const std::string& name) const
{
    auto it = std::find_if(
        impl->modules.begin(), impl->modules.end(), [&](auto& m) { return (m.name() == name); });
    if(it == impl->modules.end())
    {
        return nullptr;
    }
Shucai Xiao's avatar
Shucai Xiao committed
659

Shucai Xiao's avatar
Shucai Xiao committed
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
    return &(*it);
}

module* program::create_module(const std::string& name)
{
    auto it = impl->modules.insert(impl->modules.end(), {name});
    return &(*it);
}

module* program::get_module(const std::string& name)
{
    auto it = std::find_if(
        impl->modules.begin(), impl->modules.end(), [&](auto& m) { return (m.name() == name); });
    if(it == impl->modules.end())
    {
        return nullptr;
    }

    return &(*it);
}

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

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

std::vector<const module*> program::get_modules() const
{
Shucai Xiao's avatar
Shucai Xiao committed
687
    const module* mm = this->get_main_module();
Shucai Xiao's avatar
Shucai Xiao committed
688
689
690
691
692
693
694
    std::vector<const module*> vec_modules;
    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
695

Shucai Xiao's avatar
Shucai Xiao committed
696
697
698
699
700
701
702
703
704
705
706
std::vector<module*> program::get_modules()
{
    module* mm = this->get_main_module();
    std::vector<module*> vec_modules;
    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;
}

707
708
program& program::sort()
{
Shucai Xiao's avatar
Shucai Xiao committed
709
    for(auto& mod : this->impl->modules)
Shucai Xiao's avatar
Shucai Xiao committed
710
    {
Shucai Xiao's avatar
Shucai Xiao committed
711
        mod.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