program.cpp 19.7 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
9
#include <migraphx/env.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/time.hpp>
#include <migraphx/iterator_for.hpp>
10
#include <migraphx/pass_manager.hpp>
Paul's avatar
Paul committed
11
#include <iostream>
Paul's avatar
Paul committed
12
#include <sstream>
Paul's avatar
Paul committed
13
#include <algorithm>
Paul's avatar
Paul committed
14
#include <utility>
Paul's avatar
Paul committed
15

Paul's avatar
Paul committed
16
namespace migraphx {
Paul's avatar
Paul committed
17
inline namespace MIGRAPHX_INLINE_NS {
Paul's avatar
Paul committed
18

Paul's avatar
Paul committed
19
20
21
22
struct program_impl
{
    // A list is used to keep references to an instruction stable
    std::list<instruction> instructions;
Paul's avatar
Paul committed
23
    context ctx;
Paul's avatar
Paul committed
24
25
};

26
const operation& get_operation(instruction_ref ins) { return ins->get_operator(); }
Paul's avatar
Paul committed
27

Paul's avatar
Paul committed
28
29
30
static void print_instruction(std::ostream& os,
                              instruction_ref ins,
                              const std::unordered_map<instruction_ref, std::string>& names)
Paul's avatar
Paul committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{
    os << names.at(ins) << " = ";

    os << ins->get_operator();

    if(ins->name() == "@literal")
    {
        if(ins->get_literal().get_shape().elements() > 10)
            os << "{ ... }";
        else
            os << "{" << ins->get_literal() << "}";
    }

    if(!ins->inputs().empty())
    {
        char delim = '(';
        for(auto&& arg : ins->inputs())
        {
            os << delim << names.at(arg);
            delim = ',';
        }
        os << ")";
    }
Paul's avatar
Paul committed
54

Paul's avatar
Paul committed
55
56
57
    os << " -> " << ins->get_shape();
}

Paul's avatar
Paul committed
58
template <class F>
Khalique's avatar
Khalique committed
59
static void print_program(const program& p, F print_func)
Paul's avatar
Paul committed
60
{
61
    std::unordered_map<instruction_ref, std::string> names;
Paul's avatar
Paul committed
62
63
    int count = 0;

64
    for(auto ins : iterator_for(p))
Paul's avatar
Paul committed
65
66
    {
        std::string var_name = "@" + std::to_string(count);
Paul's avatar
Paul committed
67
        if(ins->name() == "@param")
Paul's avatar
Paul committed
68
        {
69
            var_name = any_cast<builtin::param>(ins->get_operator()).parameter;
Paul's avatar
Paul committed
70
        }
Paul's avatar
Paul committed
71
        names.emplace(ins, var_name);
Paul's avatar
Paul committed
72

Paul's avatar
Paul committed
73
74
        // TODO: Use all_of
        for(auto&& arg : ins->inputs())
Paul's avatar
Paul committed
75
        {
Paul's avatar
Paul committed
76
77
            assert(p.has_instruction(arg) && "Instruction not found");
            (void)arg;
Paul's avatar
Paul committed
78
79
        }

80
        print_func(ins, names);
Paul's avatar
Paul committed
81
82
83
84
85

        count++;
    }
}

Paul's avatar
Paul committed
86
program::program() : impl(std::make_unique<program_impl>()) {}
Paul's avatar
Paul committed
87

Paul's avatar
Paul committed
88
program::program(program&&) noexcept = default;
Paul's avatar
Paul committed
89
90
program& program::operator=(program&&) noexcept = default;
program::~program() noexcept                    = default;
Paul's avatar
Paul committed
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// copy constructor
program::program(const program& p) noexcept
{
    copy(p);
}

// copy assignment operator
program& program::operator=(const program& p) noexcept
{
    if (this != &p)
    {
        copy(p);
    }

    return *this;
}

void program::copy(const program& p)
{
    // clean the current program
    if (!impl)
    {
        impl = std::make_unique<program_impl>();
    }
    else if (!impl->instructions.empty())
    {
        remove_instructions(begin(), end());
    }
    impl->ctx = p.impl->ctx;

    std::unordered_map<instruction_ref, instruction_ref> ins_map;
    for (auto ins : iterator_for(p))
    {
        instruction_ref copy_ins{};
        if (ins->name() == "@literal")
        {
            auto l = ins->get_literal();
            copy_ins = impl->instructions.insert(impl->instructions.end(), instruction{l});
        }
        else if (ins->name() == "@param")
        {
            auto&& name  = any_cast<builtin::param>(ins->get_operator()).parameter;
            auto s = ins->get_shape();
            copy_ins = impl->instructions.insert(impl->instructions.end(), {builtin::param{std::move(name)}, std::move(s), {}});
        }
        else if (ins->name() == "@outline")
        {
            auto s = ins->get_shape();
            copy_ins = impl->instructions.insert(impl->instructions.end(), {builtin::outline{s}, s, {}});
        }
        else
        {
            // retrieve its mapped input
            auto inputs = ins->inputs();
            // ensure all inputs have its corresponding copy instructions
            assert(std::all_of(inputs.begin(), inputs.end(), [&](auto i) { return ins_map.count(i) > 0; }));
            std::vector<instruction_ref> copy_inputs(inputs.size());
            std::transform(inputs.begin(), inputs.end(), copy_inputs.begin(), [&] (auto i) { return ins_map[i]; });
            copy_ins = add_instruction(ins->get_operator(), copy_inputs);
        }

        ins_map[ins] = copy_ins;
    }
}

Paul's avatar
Paul committed
157
instruction_ref program::add_instruction(const operation& op, std::vector<instruction_ref> args)
Paul's avatar
Paul committed
158
{
Paul's avatar
Paul committed
159
    return insert_instruction(impl->instructions.end(), op, std::move(args));
Paul's avatar
Paul committed
160
}
Paul's avatar
Paul committed
161
162
163
instruction_ref program::insert_instruction(instruction_ref ins,
                                            const operation& op,
                                            std::vector<instruction_ref> args)
Paul's avatar
Paul committed
164
{
Paul's avatar
Paul committed
165
166
167
    assert(std::all_of(
               args.begin(), args.end(), [&](instruction_ref x) { return has_instruction(x); }) &&
           "Argument is not an exisiting instruction");
Paul's avatar
Paul committed
168
    assert(not starts_with(op.name(), "@"));
Paul's avatar
Paul committed
169
    shape r     = compute_shape(op, args);
Paul's avatar
Paul committed
170
    auto result = impl->instructions.insert(ins, {op, r, std::move(args)});
Paul's avatar
Paul committed
171
    instruction::backreference(result);
Paul's avatar
Paul committed
172
    assert(result->valid(begin()));
Paul's avatar
Paul committed
173
    return result;
Paul's avatar
Paul committed
174
175
}

Paul's avatar
Paul committed
176
177
178
instruction_ref program::replace_instruction(instruction_ref ins,
                                             const operation& op,
                                             std::vector<instruction_ref> args)
Paul's avatar
Paul committed
179
180
181
182
{
    assert(std::all_of(
               args.begin(), args.end(), [&](instruction_ref x) { return has_instruction(x); }) &&
           "Argument is not an exisiting instruction");
Paul's avatar
Paul committed
183
    assert(not starts_with(op.name(), "@"));
Paul's avatar
Paul committed
184

Paul's avatar
Paul committed
185
    shape r = compute_shape(op, args);
186
    instruction::replace(ins, op, r, std::move(args));
Paul's avatar
Paul committed
187
    assert(ins->valid(begin()));
Paul's avatar
Paul committed
188
189
190
    return ins;
}

Paul's avatar
Paul committed
191
instruction_ref program::replace_instruction(instruction_ref ins, instruction_ref rep)
Paul's avatar
Paul committed
192
{
Paul's avatar
Paul committed
193
194
195
    assert(has_instruction(ins));
    assert(has_instruction(rep));
    assert(ins != rep);
Shucai Xiao's avatar
Shucai Xiao committed
196

Shucai Xiao's avatar
Shucai Xiao committed
197
    if(ins == std::prev(this->end()))
Shucai Xiao's avatar
Shucai Xiao committed
198
    {
Shucai Xiao's avatar
Shucai Xiao committed
199
        return replace_instruction(ins, op::identity{}, rep);
Shucai Xiao's avatar
Shucai Xiao committed
200
201
    }

Paul's avatar
Paul committed
202
    // TODO: Should it be an error if the output is empty?
Paul's avatar
Paul committed
203
    if(ins->outputs().empty())
Paul's avatar
Paul committed
204
205
206
    {
        return rep;
    }
Paul's avatar
Paul committed
207
208
209
    // Make a copy of outputs which can be changed when calling replace_argument
    auto outputs = ins->outputs();
    for(auto out : outputs)
Paul's avatar
Paul committed
210
    {
Paul's avatar
Paul committed
211
212
        // TODO: Check for possible cycles
        if(out != rep)
Paul's avatar
Paul committed
213
        {
Paul's avatar
Paul committed
214
            instruction::replace_argument(out, ins, rep);
Paul's avatar
Paul committed
215
        }
Paul's avatar
Paul committed
216
        assert(out->valid(begin()));
Paul's avatar
Paul committed
217
    }
Paul's avatar
Paul committed
218
    // Replacement should not be dead code unless its the last instruction
Paul's avatar
Paul committed
219
    assert(!rep->outputs().empty() or rep == std::prev(end()));
Paul's avatar
Paul committed
220
    // Output of the original instruction should only be the replacement or empty
Paul's avatar
Paul committed
221
222
223
    assert(ins->outputs().empty() or std::all_of(ins->outputs().begin(),
                                                 ins->outputs().end(),
                                                 [&](auto i) { return i == rep; }));
Paul's avatar
Paul committed
224
    assert(ins->valid(begin()));
Paul's avatar
Paul committed
225
    assert(rep->valid(begin()));
Paul's avatar
Paul committed
226
227
228
    return rep;
}

Paul's avatar
Paul committed
229
instruction_ref program::remove_instruction(instruction_ref ins)
Paul's avatar
Paul committed
230
231
{
    assert(has_instruction(ins));
Paul's avatar
Paul committed
232
    assert(ins->outputs().empty());
Paul's avatar
Paul committed
233
234
235
236
    ins->clear_arguments();
    return impl->instructions.erase(ins);
}

237
238
instruction_ref program::remove_instructions(instruction_ref first, instruction_ref last)
{
Paul's avatar
Paul committed
239
240
    if(first == last)
        return first;
Paul's avatar
Paul committed
241
    // TODO: Check every element
242
    assert(has_instruction(first));
Paul's avatar
Paul committed
243
    std::for_each(first, last, [&](instruction& ins) { ins.clear_arguments(); });
Paul's avatar
Paul committed
244
    assert(std::all_of(first, last, [&](instruction& ins) { return ins.outputs().empty(); }));
245
246
247
248
249
250
251
252
253
    return impl->instructions.erase(first, last);
}

instruction_ref program::move_instruction(instruction_ref src, instruction_ref dst)
{
    impl->instructions.splice(dst, impl->instructions, src);
    return src;
}

Paul's avatar
Paul committed
254
instruction_ref program::add_literal(literal l)
Paul's avatar
Paul committed
255
{
Paul's avatar
Paul committed
256
257
258
259
    impl->instructions.emplace_front(std::move(l));
    return impl->instructions.begin();
}

Paul's avatar
Paul committed
260
instruction_ref program::add_outline(const shape& s)
Paul's avatar
Paul committed
261
262
263
{
    impl->instructions.push_front({builtin::outline{s}, s, {}});
    return impl->instructions.begin();
Paul's avatar
Paul committed
264
265
}

Paul's avatar
Paul committed
266
instruction_ref program::add_parameter(std::string name, shape s)
Paul's avatar
Paul committed
267
{
268
    assert(get_parameter_shape(name) == shape{});
Paul's avatar
Paul committed
269
    impl->instructions.push_front({builtin::param{std::move(name)}, std::move(s), {}});
Paul's avatar
Paul committed
270
271
272
    return impl->instructions.begin();
}

Paul's avatar
Paul committed
273
shape program::get_parameter_shape(std::string name) const
Paul's avatar
Paul committed
274
275
{
    auto ins = std::find_if(
Paul's avatar
Paul committed
276
        impl->instructions.begin(), impl->instructions.end(), [&](const instruction& x) {
Paul's avatar
Paul committed
277
            if(x.name() == "@param")
Paul's avatar
Paul committed
278
            {
279
                return any_cast<builtin::param>(x.get_operator()).parameter == name;
Paul's avatar
Paul committed
280
281
282
283
284
285
286
            }
            else
            {
                return false;
            }
        });
    if(ins != this->end())
Paul's avatar
Paul committed
287
        return ins->get_shape();
Paul's avatar
Paul committed
288
289
    else
        return {};
Paul's avatar
Paul committed
290
291
}

mei-ye's avatar
mei-ye committed
292
293
294
295
instruction_ref program::get_parameter(std::string name) const
{
    auto ins = std::find_if(
        impl->instructions.begin(), impl->instructions.end(), [&](const instruction& x) {
Paul's avatar
Paul committed
296
            if(x.name() == "@param")
mei-ye's avatar
mei-ye committed
297
            {
Paul's avatar
Paul committed
298
                return any_cast<builtin::param>(x.get_operator()).parameter == name;
mei-ye's avatar
mei-ye committed
299
300
301
302
303
304
305
306
307
            }
            else
            {
                return false;
            }
        });
    if(ins != this->end())
        return ins;
    else
mei-ye's avatar
mei-ye committed
308
        return this->end();
mei-ye's avatar
mei-ye committed
309
310
}

Paul's avatar
Paul committed
311
312
313
std::unordered_map<std::string, shape> program::get_parameter_shapes() const
{
    std::unordered_map<std::string, shape> result;
Paul's avatar
Paul committed
314
    for(auto&& ins : impl->instructions)
Paul's avatar
Paul committed
315
    {
Paul's avatar
Paul committed
316
        if(ins.name() == "@param")
Paul's avatar
Paul committed
317
        {
318
            auto&& name  = any_cast<builtin::param>(ins.get_operator()).parameter;
Paul's avatar
Paul committed
319
            result[name] = ins.get_shape();
Paul's avatar
Paul committed
320
321
322
323
324
        }
    }
    return result;
}

Paul's avatar
Paul committed
325
bool program::has_instruction(instruction_ref ins) const
Paul's avatar
Paul committed
326
{
Paul's avatar
Paul committed
327
328
329
330
    return std::find_if(
               impl->instructions.begin(), impl->instructions.end(), [&](const instruction& x) {
                   return std::addressof(*ins) == std::addressof(x);
               }) != impl->instructions.end();
Paul's avatar
Paul committed
331
332
}

Paul's avatar
Paul committed
333
std::size_t program::size() const { return impl->instructions.size(); }
Paul's avatar
Paul committed
334
335
instruction_ref program::begin() const { return impl->instructions.begin(); }
instruction_ref program::end() const { return impl->instructions.end(); }
336

Paul's avatar
Paul committed
337
shape program::get_shape() const { return impl->instructions.back().get_shape(); }
Paul's avatar
Paul committed
338

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

Paul's avatar
Paul committed
341
342
instruction_ref program::validate() const
{
Paul's avatar
Paul committed
343
344
    return std::find_if(impl->instructions.begin(),
                        impl->instructions.end(),
Paul's avatar
Paul committed
345
                        [&](const instruction& i) { return !i.valid(impl->instructions.begin()); });
Paul's avatar
Paul committed
346
347
}

mei-ye's avatar
mei-ye committed
348
void program::compile(const target& t, tracer trace)
Paul's avatar
Paul committed
349
{
Paul's avatar
Paul committed
350
    assert(this->validate() == impl->instructions.end());
mei-ye's avatar
mei-ye committed
351
    this->impl->ctx = t.get_context();
Paul's avatar
Paul committed
352
    if(enabled(MIGRAPHX_TRACE_COMPILE{}))
Paul's avatar
Paul committed
353
354
355
        trace = tracer{std::cout};
    trace(*this);
    trace();
356
    run_passes(*this, t.get_passes(this->impl->ctx), trace);
Paul's avatar
Paul committed
357
    auto invalid = this->validate();
Paul's avatar
Paul committed
358
359
    if(invalid != impl->instructions.end())
    {
Paul's avatar
Paul committed
360
        auto index = std::distance(impl->instructions.begin(), invalid);
Paul's avatar
Paul committed
361
        MIGRAPHX_THROW("Invalid program from compilation at instruction " + std::to_string(index));
Paul's avatar
Paul committed
362
    }
Paul's avatar
Paul committed
363
364
365
366
367
368
369
370
371
    this->finalize();
}

void program::finalize()
{
    for(auto ins : iterator_for(*this))
    {
        ins->finalize(this->impl->ctx);
    }
Paul's avatar
Paul committed
372
373
}

Paul's avatar
Paul committed
374
375
376
377
378
template <class F>
argument generic_eval(const program& p,
                      context& ctx,
                      std::unordered_map<std::string, argument> params,
                      F trace)
Paul's avatar
Paul committed
379
{
Paul's avatar
Paul committed
380
    assert(p.validate() == p.end());
381
    std::unordered_map<instruction_ref, argument> results;
Paul's avatar
Paul committed
382
    results.reserve(p.size() * 2);
Paul's avatar
Paul committed
383
384
    std::vector<argument> values;
    values.reserve(16);
385
    for(auto ins : iterator_for(p))
Paul's avatar
Paul committed
386
    {
Paul's avatar
Paul committed
387
        if(ins->name() == "@literal")
Paul's avatar
Paul committed
388
        {
Paul's avatar
Paul committed
389
            results.emplace(ins, trace(ins, [&] { return ins->get_literal().get_argument(); }));
Paul's avatar
Paul committed
390
        }
Paul's avatar
Paul committed
391
        else if(ins->name() == "@param")
Paul's avatar
Paul committed
392
        {
Paul's avatar
Paul committed
393
394
395
396
397
398
399
400
401
402
403
            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);
                    auto param = params.at(param_name);
                    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
404
        }
Paul's avatar
Paul committed
405
        else if(ins->name() == "@outline")
Paul's avatar
Paul committed
406
        {
Paul's avatar
Paul committed
407
            results.emplace(ins, trace(ins, [&] { return argument{ins->get_shape(), nullptr}; }));
Paul's avatar
Paul committed
408
        }
Paul's avatar
Paul committed
409
410
        else
        {
Paul's avatar
Paul committed
411
            values.resize(ins->inputs().size());
Paul's avatar
Paul committed
412
413
414
415
416
            std::transform(
                ins->inputs().begin(), ins->inputs().end(), values.begin(), [&](instruction_ref i) {
                    assert(results.find(i) != results.end());
                    return results[i];
                });
Paul's avatar
Paul committed
417
418
419
            results.emplace(ins, trace(ins, [&] {
                                return ins->get_operator().compute(ctx, ins->get_shape(), values);
                            }));
Paul's avatar
Paul committed
420
        }
421
        assert(results.find(ins) != results.end());
Paul's avatar
Paul committed
422
    }
423
    return results.at(std::prev(p.end()));
Paul's avatar
Paul committed
424
425
}

Paul's avatar
Paul committed
426
427
argument program::eval(std::unordered_map<std::string, argument> params) const
{
Paul's avatar
Paul committed
428
429
    auto& ctx = this->impl->ctx;
#ifndef NDEBUG
Paul's avatar
Paul committed
430
    auto sctx          = ctx;
Paul's avatar
Paul committed
431
432
433
    auto check_context = [&](auto f) {
        assert(is_shared(ctx, sctx));
        auto x = f();
Paul's avatar
Paul committed
434
        sctx   = ctx;
Paul's avatar
Paul committed
435
436
437
        return x;
    };
#else
Paul's avatar
Paul committed
438
    auto check_context = [](auto f) { return f(); };
Paul's avatar
Paul committed
439
#endif
Paul's avatar
Paul committed
440
    if(enabled(MIGRAPHX_TRACE_EVAL{}))
Paul's avatar
Paul committed
441
    {
Paul's avatar
Paul committed
442
        return generic_eval(*this, ctx, std::move(params), [&](auto& ins, auto f) {
Paul's avatar
Paul committed
443
            ctx.finish();
Paul's avatar
Paul committed
444
445
            std::cout << "Run instruction: ";
            this->debug_print(ins);
Paul's avatar
Paul committed
446
            return check_context(f);
Paul's avatar
Paul committed
447
        });
Paul's avatar
Paul committed
448
449
450
451
    }
    else
    {
        return generic_eval(
Paul's avatar
Paul committed
452
            *this, ctx, std::move(params), [&](auto&, auto f) { return check_context(f); });
Paul's avatar
Paul committed
453
    }
Paul's avatar
Paul committed
454
455
}

Paul's avatar
Paul committed
456
457
458
double common_average(const std::vector<double>& v)
{
    std::size_t n = v.size() / 4;
Paul's avatar
Paul committed
459
460
    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
461
462
}

Paul's avatar
Paul committed
463
464
465
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
466
    auto& ctx          = this->impl->ctx;
Paul's avatar
Paul committed
467
468
    // Run once by itself
    eval(params);
Paul's avatar
Paul committed
469
    ctx.finish();
Paul's avatar
Paul committed
470
    // Run and time entire program
Paul's avatar
Paul committed
471
472
    std::vector<double> total_vec;
    total_vec.reserve(n);
Paul's avatar
Paul committed
473
    for(std::size_t i = 0; i < n; i++)
Paul's avatar
Paul committed
474
    {
Paul's avatar
Paul committed
475
476
477
478
        total_vec.push_back(time<milliseconds>([&] {
            eval(params);
            ctx.finish();
        }));
Paul's avatar
Paul committed
479
    }
Paul's avatar
Paul committed
480
481
    std::sort(total_vec.begin(), total_vec.end());
    std::unordered_map<instruction_ref, std::vector<double>> ins_vec;
Paul's avatar
Paul committed
482
    // Fill the map
Paul's avatar
Paul committed
483
    generic_eval(*this, ctx, params, [&](auto ins, auto) {
Paul's avatar
Paul committed
484
        ins_vec[ins].reserve(n);
Paul's avatar
Paul committed
485
486
        return argument{};
    });
Paul's avatar
Paul committed
487
    // Run and time each instruction
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
        generic_eval(*this, ctx, params, [&](auto ins, auto f) {
491
            argument result;
Paul's avatar
Paul committed
492
493
494
495
            ins_vec[ins].push_back(time<milliseconds>([&] {
                result = f();
                ctx.finish();
            }));
496
            return result;
Paul's avatar
Paul committed
497
498
        });
    }
Paul's avatar
Paul committed
499
500
    for(auto&& p : ins_vec)
        std::sort(p.second.begin(), p.second.end());
Paul's avatar
Paul committed
501
    // Run and time implicit overhead
Paul's avatar
Paul committed
502
503
    std::vector<double> overhead_vec;
    overhead_vec.reserve(n);
Paul's avatar
Paul committed
504
    for(std::size_t i = 0; i < n; i++)
Paul's avatar
Paul committed
505
    {
Paul's avatar
Paul committed
506
        overhead_vec.push_back(time<milliseconds>([&] { dry_run(params); }));
Paul's avatar
Paul committed
507
508
    }

Paul's avatar
Paul committed
509
    double total_time             = common_average(total_vec);
Paul's avatar
Paul committed
510
    double rate                   = 1000.0 / total_time;
Paul's avatar
Paul committed
511
    double overhead_time          = common_average(overhead_vec);
Paul's avatar
Paul committed
512
    double overhead_percent       = overhead_time * 100.0 / total_time;
Paul's avatar
Paul committed
513
    double total_instruction_time = 0.0;
Paul's avatar
Paul committed
514
    std::unordered_map<std::string, double> op_times;
Paul's avatar
Paul committed
515
    for(auto&& p : ins_vec)
Paul's avatar
Paul committed
516
517
    {
        double avg = common_average(p.second);
Paul's avatar
Paul committed
518
        op_times[p.first->name()] += avg;
Paul's avatar
Paul committed
519
520
        total_instruction_time += avg;
    }
Paul's avatar
Paul committed
521
522
    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
523

524
    print_program(*this, [&](auto ins, const auto& names) {
Khalique's avatar
Khalique committed
525
        print_instruction(std::cout, ins, names);
Paul's avatar
Paul committed
526
527
528
        double avg     = common_average(ins_vec[ins]);
        double percent = std::ceil(100.0 * avg / total_instruction_time);
        os << ": " << avg << "ms, " << percent << "%";
529
        os << std::endl;
Paul's avatar
Paul committed
530
    });
Paul's avatar
Paul committed
531
532
533

    os << std::endl;
    os << "Summary:" << std::endl;
Paul's avatar
Paul committed
534
    for(auto&& p : op_times)
Paul's avatar
Paul committed
535
    {
Paul's avatar
Paul committed
536
537
        auto&& name    = p.first;
        double avg     = p.second;
Paul's avatar
Paul committed
538
539
540
541
542
        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
543

Paul's avatar
Paul committed
544
    os << "Rate: " << rate << "/sec" << std::endl;
Paul's avatar
Paul committed
545
546
    os << "Total time: " << total_time << "ms" << std::endl;
    os << "Total instructions time: " << total_instruction_time << "ms" << std::endl;
Paul's avatar
Paul committed
547
548
549
550
    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
551
552
}

Paul's avatar
Paul committed
553
554
void program::debug_print() const { std::cout << *this << std::endl; }
void program::debug_print(instruction_ref ins) const
Paul's avatar
Paul committed
555
{
Paul's avatar
Paul committed
556
557
558
559
560
561
562
563
564
565
    if(ins == this->end())
    {
        std::cout << "End instruction" << std::endl;
        return;
    }
    if(not has_instruction(ins))
    {
        std::cout << "Instruction not part of program" << std::endl;
        return;
    }
Paul's avatar
Paul committed
566
    std::stringstream ss;
567
    print_program(*this, [&](auto x, const auto& names) {
Paul's avatar
Paul committed
568
        if(x == ins)
Paul's avatar
Paul committed
569
570
571
572
573
574
        {
            print_instruction(std::cout, x, names);
            std::cout << std::endl;
        }
    });
}
Paul's avatar
Paul committed
575
void program::debug_print(const std::vector<instruction_ref>& inss) const
Paul's avatar
Paul committed
576
{
Paul's avatar
Paul committed
577
    for(auto ins : inss)
Paul's avatar
Paul committed
578
579
580
581
        debug_print(ins);
    std::cout << std::endl;
}

Khalique's avatar
Khalique committed
582
static std::string enclose_name(const std::string& name)
583
{
Khalique's avatar
Khalique committed
584
    return '"' + replace_string(name, "\"", "\\\"") + '"';
585
586
}

587
588
589
590
void program::print_graph(std::ostream& os) const
{
    os << "digraph {" << std::endl;
    os << "\trankdir=LR;" << std::endl;
591
    print_program(*this, [&](auto ins, const auto& names) {
Khalique's avatar
Khalique committed
592
593
        os << "\t" << enclose_name(names.at(ins))
           << "[label=" << enclose_name(to_string(ins->get_operator())) << "];";
594
595
596
597
598
599
600
601
602
603
604
        os << std::endl;
        if(!ins->inputs().empty())
        {
            for(auto&& arg : ins->inputs())
            {
                os << "\t" << enclose_name(names.at(arg)) << " -> " << enclose_name(names.at(ins));
                os << "[label=" << enclose_name(to_string(ins->get_shape())) << "];";
                os << std::endl;
            }
        }
    });
605
606
607
    os << "}" << std::endl;
}

Paul's avatar
Paul committed
608
609
void program::dry_run(std::unordered_map<std::string, argument> params) const
{
Paul's avatar
Paul committed
610
    auto& ctx = this->impl->ctx;
Paul's avatar
Paul committed
611
    generic_eval(*this, ctx, std::move(params), [](auto&&...) { return argument{}; });
Paul's avatar
Paul committed
612
613
}

Paul's avatar
Paul committed
614
615
void program::annotate(std::ostream& os, std::function<void(instruction_ref)> a) const
{
616
617
618
619
620
    print_program(*this, [&](auto ins, const auto& names) {
        print_instruction(os, ins, names);
        a(ins);
        os << std::endl;
    });
Paul's avatar
Paul committed
621
622
}

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

Paul's avatar
Paul committed
625
std::ostream& operator<<(std::ostream& os, const program& p)
Paul's avatar
Paul committed
626
{
627
628
629
630
    print_program(p, [&](auto ins, const auto& names) {
        print_instruction(os, ins, names);
        os << std::endl;
    });
Paul's avatar
Paul committed
631
    return os;
Paul's avatar
Paul committed
632
}
Paul's avatar
Paul committed
633

Paul's avatar
Paul committed
634
} // namespace MIGRAPHX_INLINE_NS
Paul's avatar
Paul committed
635
} // namespace migraphx