program.cpp 23.8 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
        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

Shucai Xiao's avatar
Shucai Xiao committed
319
320
321
    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
322
    {
Shucai Xiao's avatar
Shucai Xiao committed
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
356
357
358
359
360
361
        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
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
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
435
436
437
438
439
440
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;
    }
}

441
442
443
444
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
445
446
447
448
    {
        MIGRAPHX_THROW("Warning: Program version mismatch");
    }

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

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

472
473
474
    this->finalize();
}

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

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

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

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

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

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

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

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

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

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

Shucai Xiao's avatar
Shucai Xiao committed
613
614
615
616
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
617
{
Shucai Xiao's avatar
Shucai Xiao committed
618
    for(const auto& mod : this->impl->modules)
619
    {
Shucai Xiao's avatar
Shucai Xiao committed
620
        names = mod.print(print_func, names);
621
622
623
    }
}

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

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

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

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

Shucai Xiao's avatar
Shucai Xiao committed
657
658
659
660
661
662
663
664
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
665

Shucai Xiao's avatar
Shucai Xiao committed
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
    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
693
    const module* mm = this->get_main_module();
Shucai Xiao's avatar
Shucai Xiao committed
694
695
696
697
698
699
700
    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
701

Shucai Xiao's avatar
Shucai Xiao committed
702
703
704
705
706
707
708
709
710
711
712
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;
}

713
714
program& program::sort()
{
Shucai Xiao's avatar
Shucai Xiao committed
715
    for(auto& mod : this->impl->modules)
Shucai Xiao's avatar
Shucai Xiao committed
716
    {
Shucai Xiao's avatar
Shucai Xiao committed
717
        mod.sort();
Shucai Xiao's avatar
Shucai Xiao committed
718
719
    }

720
721
722
    return *this;
}

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

Paul's avatar
Paul committed
725
std::ostream& operator<<(std::ostream& os, const program& p)
Paul's avatar
Paul committed
726
{
Shucai Xiao's avatar
Shucai Xiao committed
727
728
729
    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
730
    {
Shucai Xiao's avatar
Shucai Xiao committed
731
732
733
734
735
736
737
        os << "module: \"" << mod->name() << "\"" << std::endl;
        names = mod->print(
            [&](auto ins, auto ins_names) {
                instruction::print(os, ins, ins_names);
                os << std::endl;
            },
            names);
738
        os << std::endl;
Shucai Xiao's avatar
Shucai Xiao committed
739
740
    }

Paul's avatar
Paul committed
741
    return os;
Paul's avatar
Paul committed
742
}
Paul's avatar
Paul committed
743

Paul's avatar
Paul committed
744
} // namespace MIGRAPHX_INLINE_NS
Paul's avatar
Paul committed
745
} // namespace migraphx