<commit_before>#include "ncurses.hh"

#include "display_buffer.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"
#include "event_manager.hh"

#include <map>

#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>

namespace Kakoune
{

static void set_attribute(int attribute, bool on)
{
    if (on)
        attron(attribute);
    else
        attroff(attribute);
}

static int nc_color(Color color)
{
    switch (color)
    {
    case Color::Black:   return COLOR_BLACK;
    case Color::Red:     return COLOR_RED;
    case Color::Green:   return COLOR_GREEN;
    case Color::Yellow:  return COLOR_YELLOW;
    case Color::Blue:    return COLOR_BLUE;
    case Color::Magenta: return COLOR_MAGENTA;
    case Color::Cyan:    return COLOR_CYAN;
    case Color::White:   return COLOR_WHITE;

    case Color::Default:
    default:
        return -1;
    }
}

static int get_color_pair(Color fg_color, Color bg_color)
{
    static std::map<std::pair<Color, Color>, int> colorpairs;
    static int next_pair = 1;

    std::pair<Color, Color> colorpair(fg_color, bg_color);

    auto it = colorpairs.find(colorpair);
    if (it != colorpairs.end())
        return it->second;
    else
    {
        init_pair(next_pair, nc_color(fg_color), nc_color(bg_color));
        colorpairs[colorpair] = next_pair;
        return next_pair++;
    }
}

static void set_color(Color fg_color, Color bg_color)
{
    static int current_pair = -1;

    if (current_pair != -1)
        attroff(COLOR_PAIR(current_pair));

    if (fg_color != Color::Default or bg_color != Color::Default)
    {
        current_pair = get_color_pair(fg_color, bg_color);
        attron(COLOR_PAIR(current_pair));
    }
}

static NCursesUI* signal_ui = nullptr;
void on_term_resize(int)
{
    int fd = open("/dev/tty", O_RDWR);
    winsize ws;
    if (fd == -1 or ioctl(fd, TIOCGWINSZ, (void*)&ws) != 0)
        return;
    close(fd);
    resizeterm(ws.ws_row, ws.ws_col);
    ungetch(KEY_RESIZE);
    signal_ui->update_dimensions();
    EventManager::instance().force_signal(0);
}

void on_sigint(int)
{
    ungetch(CTRL('c'));
    EventManager::instance().force_signal(0);
}

NCursesUI::NCursesUI()
{
    //setlocale(LC_CTYPE, "");
    initscr();
    cbreak();
    noecho();
    nonl();
    intrflush(stdscr, false);
    keypad(stdscr, true);
    curs_set(0);
    start_color();
    use_default_colors();
    ESCDELAY=25;

    m_menu_fg = get_color_pair(Color::Blue, Color::Cyan);
    m_menu_bg = get_color_pair(Color::Cyan, Color::Blue);

    update_dimensions();

    assert(signal_ui == nullptr);
    signal_ui = this;
    signal(SIGWINCH, on_term_resize);
    signal(SIGINT, on_sigint);
}

NCursesUI::~NCursesUI()
{
    endwin();
}

static void redraw(WINDOW* menu_win)
{
    wnoutrefresh(stdscr);
    if (menu_win)
    {
        redrawwin(menu_win);
        wnoutrefresh(menu_win);
    }
    doupdate();
}
using Utf8Policy = utf8::InvalidBytePolicy::Pass;
using Utf8Iterator = utf8::utf8_iterator<String::iterator, Utf8Policy>;
void addutf8str(Utf8Iterator begin, Utf8Iterator end)
{
    assert(begin <= end);
    while (begin != end)
        addch(*begin++);
}

void NCursesUI::update_dimensions()
{
    int max_x,max_y;
    getmaxyx(stdscr, max_y, max_x);
    max_y -= 1;
    m_dimensions = { max_y, max_x };
}

void NCursesUI::draw(const DisplayBuffer& display_buffer,
                     const String& mode_line)
{
    LineCount line_index = 0;
    for (const DisplayLine& line : display_buffer.lines())
    {
        move((int)line_index, 0);
        clrtoeol();
        CharCount col_index = 0;
        for (const DisplayAtom& atom : line)
        {
            set_attribute(A_UNDERLINE, atom.attribute & Underline);
            set_attribute(A_REVERSE, atom.attribute & Reverse);
            set_attribute(A_BLINK, atom.attribute & Blink);
            set_attribute(A_BOLD, atom.attribute & Bold);

            set_color(atom.fg_color, atom.bg_color);

            String content = atom.content.content();
            if (content[content.length()-1] == '\n' and
                content.char_length() - 1 < m_dimensions.column - col_index)
            {
                addutf8str(Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
                addch(' ');
            }
            else
            {
                Utf8Iterator begin(content.begin()), end(content.end());
                if (end - begin > m_dimensions.column - col_index)
                    end = begin + (m_dimensions.column - col_index);
                addutf8str(begin, end);
                col_index += end - begin;
            }
        }
        ++line_index;
    }

    set_attribute(A_UNDERLINE, 0);
    set_attribute(A_REVERSE, 0);
    set_attribute(A_BLINK, 0);
    set_attribute(A_BOLD, 0);
    set_color(Color::Blue, Color::Black);
    for (;line_index < m_dimensions.line; ++line_index)
    {
        move((int)line_index, 0);
        clrtoeol();
        addch('~');
    }

    set_color(Color::Cyan, Color::Black);
    draw_status();
    CharCount status_len = mode_line.char_length();
    // only draw mode_line if it does not overlap one status line
    if (m_dimensions.column - m_status_line.char_length() > status_len + 1)
    {
        move((int)m_dimensions.line, (int)(m_dimensions.column - status_len));
        addutf8str(Utf8Iterator(mode_line.begin()),
                   Utf8Iterator(mode_line.end()));
    }
    redraw(m_menu_win);
}

struct getch_iterator
{
    int operator*() { return getch(); }
    getch_iterator& operator++() { return *this; }
    getch_iterator& operator++(int) { return *this; }
};

bool NCursesUI::is_key_available()
{
    timeout(0);
    const int c = getch();
    if (c != ERR)
        ungetch(c);
    timeout(-1);
    return c != ERR;
}

Key NCursesUI::get_key()
{
    const unsigned c = getch();
    if (c > 0 and c < 27)
    {
        return {Key::Modifiers::Control, c - 1 + 'a'};
    }
    else if (c == 27)
    {
        timeout(0);
        const Codepoint new_c = getch();
        timeout(-1);
        if (new_c != ERR)
            return {Key::Modifiers::Alt, new_c};
        else
            return Key::Escape;
    }
    else switch (c)
    {
    case KEY_BACKSPACE: return Key::Backspace;
    case KEY_UP: return Key::Up;
    case KEY_DOWN: return Key::Down;
    case KEY_LEFT: return Key::Left;
    case KEY_RIGHT: return Key::Right;
    case KEY_PPAGE: return Key::PageUp;
    case KEY_NPAGE: return Key::PageDown;
    case KEY_BTAB: return Key::BackTab;
    }

    if (c < 256)
    {
       ungetch(c);
       return utf8::codepoint(getch_iterator{});
    }
    return Key::Invalid;
}

void NCursesUI::draw_status()
{
    move((int)m_dimensions.line, 0);
    clrtoeol();
    if (m_status_cursor == -1)
       addutf8str(m_status_line.begin(), m_status_line.end());
    else
    {
        auto cursor_it = utf8::advance(m_status_line.begin(), m_status_line.end(),
                                       (int)m_status_cursor);
        auto end = m_status_line.end();
        addutf8str(m_status_line.begin(), cursor_it);
        set_attribute(A_REVERSE, 1);
        addch((cursor_it == end) ? ' ' : utf8::codepoint<Utf8Policy>(cursor_it));
        set_attribute(A_REVERSE, 0);
        if (cursor_it != end)
            addutf8str(utf8::next(cursor_it), end);
    }
}

void NCursesUI::print_status(const String& status, CharCount cursor_pos)
{
    m_status_line   = status;
    m_status_cursor = cursor_pos;
    draw_status();
    redraw(m_menu_win);
}

void NCursesUI::menu_show(const memoryview<String>& choices,
                          const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_menu == nullptr);
    assert(m_menu_win == nullptr);
    assert(m_choices.empty());
    assert(m_items.empty());

    int max_x,max_y;
    getmaxyx(stdscr, max_y, max_x);
    max_x -= (int)anchor.column;

    m_choices.reserve(choices.size());
    CharCount longest = 0;
    for (auto& choice : choices)
    {
        m_choices.push_back(choice.substr(0_char, std::min(max_x-1, 200)));
        m_items.emplace_back(new_item(m_choices.back().c_str(), ""));
        longest = std::max(longest, m_choices.back().char_length());
    }
    m_items.push_back(nullptr);
    longest += 1;

    int columns = (style == MenuStyle::Prompt) ? (max_x / (int)longest) : 1;
    int lines = std::min(10, (int)ceilf((float)m_choices.size()/columns));

    m_menu_pos = { anchor.line+1, anchor.column };
    if (m_menu_pos.line + lines >= max_y)
        m_menu_pos.line = anchor.line - lines;
    m_menu_size = { lines, columns == 1 ? longest : max_x };

    m_menu = new_menu(&m_items[0]);
    m_menu_win = newwin((int)m_menu_size.line, (int)m_menu_size.column,
                        (int)m_menu_pos.line,  (int)m_menu_pos.column);
    set_menu_win(m_menu, m_menu_win);
    set_menu_format(m_menu, lines, columns);
    set_menu_mark(m_menu, nullptr);
    set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
    set_menu_back(m_menu, COLOR_PAIR(m_menu_bg));
    post_menu(m_menu);
}

void NCursesUI::menu_select(int selected)
{
    // last item in m_items is the nullptr, hence the - 1
    if (selected >= 0 and selected < m_items.size() - 1)
    {
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
        set_current_item(m_menu, m_items[selected]);
    }
    else
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_bg));
}

void NCursesUI::menu_hide()
{
    if (not m_menu)
        return;
    unpost_menu(m_menu);
    free_menu(m_menu);
    for (auto item : m_items)
       if (item)
           free_item(item);
    m_menu = nullptr;
    delwin(m_menu_win);
    m_menu_win = nullptr;
    m_items.clear();
    m_choices.clear();
}

DisplayCoord NCursesUI::dimensions()
{
    return m_dimensions;
}

}
<commit_msg>NCurses: use Default bg color for status line<commit_after>#include "ncurses.hh"

#include "display_buffer.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"
#include "event_manager.hh"

#include <map>

#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>

namespace Kakoune
{

static void set_attribute(int attribute, bool on)
{
    if (on)
        attron(attribute);
    else
        attroff(attribute);
}

static int nc_color(Color color)
{
    switch (color)
    {
    case Color::Black:   return COLOR_BLACK;
    case Color::Red:     return COLOR_RED;
    case Color::Green:   return COLOR_GREEN;
    case Color::Yellow:  return COLOR_YELLOW;
    case Color::Blue:    return COLOR_BLUE;
    case Color::Magenta: return COLOR_MAGENTA;
    case Color::Cyan:    return COLOR_CYAN;
    case Color::White:   return COLOR_WHITE;

    case Color::Default:
    default:
        return -1;
    }
}

static int get_color_pair(Color fg_color, Color bg_color)
{
    static std::map<std::pair<Color, Color>, int> colorpairs;
    static int next_pair = 1;

    std::pair<Color, Color> colorpair(fg_color, bg_color);

    auto it = colorpairs.find(colorpair);
    if (it != colorpairs.end())
        return it->second;
    else
    {
        init_pair(next_pair, nc_color(fg_color), nc_color(bg_color));
        colorpairs[colorpair] = next_pair;
        return next_pair++;
    }
}

static void set_color(Color fg_color, Color bg_color)
{
    static int current_pair = -1;

    if (current_pair != -1)
        attroff(COLOR_PAIR(current_pair));

    if (fg_color != Color::Default or bg_color != Color::Default)
    {
        current_pair = get_color_pair(fg_color, bg_color);
        attron(COLOR_PAIR(current_pair));
    }
}

static NCursesUI* signal_ui = nullptr;
void on_term_resize(int)
{
    int fd = open("/dev/tty", O_RDWR);
    winsize ws;
    if (fd == -1 or ioctl(fd, TIOCGWINSZ, (void*)&ws) != 0)
        return;
    close(fd);
    resizeterm(ws.ws_row, ws.ws_col);
    ungetch(KEY_RESIZE);
    signal_ui->update_dimensions();
    EventManager::instance().force_signal(0);
}

void on_sigint(int)
{
    ungetch(CTRL('c'));
    EventManager::instance().force_signal(0);
}

NCursesUI::NCursesUI()
{
    //setlocale(LC_CTYPE, "");
    initscr();
    cbreak();
    noecho();
    nonl();
    intrflush(stdscr, false);
    keypad(stdscr, true);
    curs_set(0);
    start_color();
    use_default_colors();
    ESCDELAY=25;

    m_menu_fg = get_color_pair(Color::Blue, Color::Cyan);
    m_menu_bg = get_color_pair(Color::Cyan, Color::Blue);

    update_dimensions();

    assert(signal_ui == nullptr);
    signal_ui = this;
    signal(SIGWINCH, on_term_resize);
    signal(SIGINT, on_sigint);
}

NCursesUI::~NCursesUI()
{
    endwin();
}

static void redraw(WINDOW* menu_win)
{
    wnoutrefresh(stdscr);
    if (menu_win)
    {
        redrawwin(menu_win);
        wnoutrefresh(menu_win);
    }
    doupdate();
}
using Utf8Policy = utf8::InvalidBytePolicy::Pass;
using Utf8Iterator = utf8::utf8_iterator<String::iterator, Utf8Policy>;
void addutf8str(Utf8Iterator begin, Utf8Iterator end)
{
    assert(begin <= end);
    while (begin != end)
        addch(*begin++);
}

void NCursesUI::update_dimensions()
{
    int max_x,max_y;
    getmaxyx(stdscr, max_y, max_x);
    max_y -= 1;
    m_dimensions = { max_y, max_x };
}

void NCursesUI::draw(const DisplayBuffer& display_buffer,
                     const String& mode_line)
{
    LineCount line_index = 0;
    for (const DisplayLine& line : display_buffer.lines())
    {
        move((int)line_index, 0);
        clrtoeol();
        CharCount col_index = 0;
        for (const DisplayAtom& atom : line)
        {
            set_attribute(A_UNDERLINE, atom.attribute & Underline);
            set_attribute(A_REVERSE, atom.attribute & Reverse);
            set_attribute(A_BLINK, atom.attribute & Blink);
            set_attribute(A_BOLD, atom.attribute & Bold);

            set_color(atom.fg_color, atom.bg_color);

            String content = atom.content.content();
            if (content[content.length()-1] == '\n' and
                content.char_length() - 1 < m_dimensions.column - col_index)
            {
                addutf8str(Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
                addch(' ');
            }
            else
            {
                Utf8Iterator begin(content.begin()), end(content.end());
                if (end - begin > m_dimensions.column - col_index)
                    end = begin + (m_dimensions.column - col_index);
                addutf8str(begin, end);
                col_index += end - begin;
            }
        }
        ++line_index;
    }

    set_attribute(A_UNDERLINE, 0);
    set_attribute(A_REVERSE, 0);
    set_attribute(A_BLINK, 0);
    set_attribute(A_BOLD, 0);
    set_color(Color::Blue, Color::Black);
    for (;line_index < m_dimensions.line; ++line_index)
    {
        move((int)line_index, 0);
        clrtoeol();
        addch('~');
    }

    set_color(Color::Cyan, Color::Default);
    draw_status();
    CharCount status_len = mode_line.char_length();
    // only draw mode_line if it does not overlap one status line
    if (m_dimensions.column - m_status_line.char_length() > status_len + 1)
    {
        move((int)m_dimensions.line, (int)(m_dimensions.column - status_len));
        addutf8str(Utf8Iterator(mode_line.begin()),
                   Utf8Iterator(mode_line.end()));
    }
    redraw(m_menu_win);
}

struct getch_iterator
{
    int operator*() { return getch(); }
    getch_iterator& operator++() { return *this; }
    getch_iterator& operator++(int) { return *this; }
};

bool NCursesUI::is_key_available()
{
    timeout(0);
    const int c = getch();
    if (c != ERR)
        ungetch(c);
    timeout(-1);
    return c != ERR;
}

Key NCursesUI::get_key()
{
    const unsigned c = getch();
    if (c > 0 and c < 27)
    {
        return {Key::Modifiers::Control, c - 1 + 'a'};
    }
    else if (c == 27)
    {
        timeout(0);
        const Codepoint new_c = getch();
        timeout(-1);
        if (new_c != ERR)
            return {Key::Modifiers::Alt, new_c};
        else
            return Key::Escape;
    }
    else switch (c)
    {
    case KEY_BACKSPACE: return Key::Backspace;
    case KEY_UP: return Key::Up;
    case KEY_DOWN: return Key::Down;
    case KEY_LEFT: return Key::Left;
    case KEY_RIGHT: return Key::Right;
    case KEY_PPAGE: return Key::PageUp;
    case KEY_NPAGE: return Key::PageDown;
    case KEY_BTAB: return Key::BackTab;
    }

    if (c < 256)
    {
       ungetch(c);
       return utf8::codepoint(getch_iterator{});
    }
    return Key::Invalid;
}

void NCursesUI::draw_status()
{
    move((int)m_dimensions.line, 0);
    clrtoeol();
    if (m_status_cursor == -1)
       addutf8str(m_status_line.begin(), m_status_line.end());
    else
    {
        auto cursor_it = utf8::advance(m_status_line.begin(), m_status_line.end(),
                                       (int)m_status_cursor);
        auto end = m_status_line.end();
        addutf8str(m_status_line.begin(), cursor_it);
        set_attribute(A_REVERSE, 1);
        addch((cursor_it == end) ? ' ' : utf8::codepoint<Utf8Policy>(cursor_it));
        set_attribute(A_REVERSE, 0);
        if (cursor_it != end)
            addutf8str(utf8::next(cursor_it), end);
    }
}

void NCursesUI::print_status(const String& status, CharCount cursor_pos)
{
    m_status_line   = status;
    m_status_cursor = cursor_pos;
    draw_status();
    redraw(m_menu_win);
}

void NCursesUI::menu_show(const memoryview<String>& choices,
                          const DisplayCoord& anchor, MenuStyle style)
{
    assert(m_menu == nullptr);
    assert(m_menu_win == nullptr);
    assert(m_choices.empty());
    assert(m_items.empty());

    int max_x,max_y;
    getmaxyx(stdscr, max_y, max_x);
    max_x -= (int)anchor.column;

    m_choices.reserve(choices.size());
    CharCount longest = 0;
    for (auto& choice : choices)
    {
        m_choices.push_back(choice.substr(0_char, std::min(max_x-1, 200)));
        m_items.emplace_back(new_item(m_choices.back().c_str(), ""));
        longest = std::max(longest, m_choices.back().char_length());
    }
    m_items.push_back(nullptr);
    longest += 1;

    int columns = (style == MenuStyle::Prompt) ? (max_x / (int)longest) : 1;
    int lines = std::min(10, (int)ceilf((float)m_choices.size()/columns));

    m_menu_pos = { anchor.line+1, anchor.column };
    if (m_menu_pos.line + lines >= max_y)
        m_menu_pos.line = anchor.line - lines;
    m_menu_size = { lines, columns == 1 ? longest : max_x };

    m_menu = new_menu(&m_items[0]);
    m_menu_win = newwin((int)m_menu_size.line, (int)m_menu_size.column,
                        (int)m_menu_pos.line,  (int)m_menu_pos.column);
    set_menu_win(m_menu, m_menu_win);
    set_menu_format(m_menu, lines, columns);
    set_menu_mark(m_menu, nullptr);
    set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
    set_menu_back(m_menu, COLOR_PAIR(m_menu_bg));
    post_menu(m_menu);
}

void NCursesUI::menu_select(int selected)
{
    // last item in m_items is the nullptr, hence the - 1
    if (selected >= 0 and selected < m_items.size() - 1)
    {
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_fg));
        set_current_item(m_menu, m_items[selected]);
    }
    else
        set_menu_fore(m_menu, COLOR_PAIR(m_menu_bg));
}

void NCursesUI::menu_hide()
{
    if (not m_menu)
        return;
    unpost_menu(m_menu);
    free_menu(m_menu);
    for (auto item : m_items)
       if (item)
           free_item(item);
    m_menu = nullptr;
    delwin(m_menu_win);
    m_menu_win = nullptr;
    m_items.clear();
    m_choices.clear();
}

DisplayCoord NCursesUI::dimensions()
{
    return m_dimensions;
}

}
<|endoftext|>


<commit_before>#include "tensorflow/core/common_runtime/GraphLogger.h"
#include "tensorflow/core/framework/step_stats.pb.h"
namespace tensorflow {
    GraphLogger& GraphLogger::getInstance() {
        static GraphLogger instance;
        return instance;
    }

    vertex *GraphLogger::addvertex(const string &name)
    {
        mutex_lock l(work_mtx);
        if (work.count(name) == 0) {
            return new vertex(name);
        } else {
            cout << "\nVertex already exists!";
            return work[name];
        }
    }

    void GraphLogger::addedge(const string &from, const string &to, double cost)
    {
        vertex *f = addvertex(from);
        vertex *t = addvertex(to);
        pair<double, vertex *> edge = make_pair(cost, t);
        //f->adj_mtx.lock();
        //f->adj.push_back(edge);
        //f->adj_mtx.unlock();
        addadj(f, edge);
    }

    void GraphLogger::addadj(vertex *v, pair<double, vertex *> edge) {
        v->adj_mtx.lock();
        v->adj.push_back(edge);
        v->adj_mtx.unlock();
    }

    void GraphLogger::addnodes(string node_name) {
        mutex_lock l(recv_nodes_mtx);
        recv_nodes.push_back(node_name);
    }

    size_t GraphLogger::get_memory() {
        memory_mtx.lock();
        mutex_lock l(recv_nodes_mtx);
        memory += sizeof(work);
        memory += sizeof(recv_nodes);
        for (auto item : work) {
            item.second->adj_mtx.lock();
            memory += sizeof(*(item.second));
            item.second->adj_mtx.unlock();
        }
        size_t result = memory;
        memory_mtx.unlock();
        return result;
    }

    void GraphLogger::add_step_stats(NodeExecStats* nt, const Node *node)
    {
        if (nt) {
            log_mtx.lock();
            FILE *file = fopen("/tmp/step_stat.log", "a+");
            fprintf(file, "node_name: ");
            fprintf(file, nt->node_name().c_str());
            fprintf(file, "\n");

            fprintf(file, "all_start_micros: ");
            fprintf(file, "%ld", nt->all_start_micros());
            fprintf(file, "\n");

            fprintf(file, "op_start_rel_micros: ");
            fprintf(file, "%ld", nt->op_start_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "op_end_rel_micros: ");
            fprintf(file, "%ld", nt->op_end_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "all_end_rel_micros: ");
            fprintf(file, "%ld", nt->all_end_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "scheduled_micros: ");
            fprintf(file, "%ld", nt->scheduled_micros());
            fprintf(file, "\n");

            fprintf(file, "schedule_start_skew: ");
            fprintf(file, "%ld", nt->all_start_micros()- nt->scheduled_micros());
            fprintf(file, "\n");

            fprintf(file, "thread_id: ");
            fprintf(file, "%ld", nt->thread_id());
            fprintf(file, "\n");

            fprintf(file, "timeline_label: ");
            fprintf(file, nt->timeline_label().c_str());
            fprintf(file, "\n");

            fprintf(file, "\n");
            fflush(file);

            // update the information
            vertex *v = addvertex(nt->node_name());
            v->all_start_micros = nt->all_start_micros();
            v->op_start_rel_micros = nt->op_start_rel_micros();
            v->op_end_rel_micros = nt->op_end_rel_micros();
            v->all_end_rel_micros = nt->all_end_rel_micros();
            //v->total_bytes = ;
            //v->peak_bytes;
            v->timeline_label = nt->timeline_label();
            v->scheduled_micros = nt->scheduled_micros();
            v->thread_id = nt->thread_id();

            // add informaion in node for
            // 1. sender inforamtion of receiver
            // 2. consum operation for receiver
            const NodeDef& def = node->def();
            if (IsRecv(node)) {
                string send_device;
                TF_CHECK_OK(GetNodeAttr(def, "send_device", &send_device));
                v->is_recv = true;
                v->sender = send_device;
                //currently no mutex lock is needed now
                //recv_nodes_mtx.lock();
                addnodes(nt->node_name());
                //recv_nodes_mtx.unlock();
            }
            std::vector<StringPiece> inputs = std::vector<StringPiece>(def.input().begin(), def.input().end());
            for (auto& str : inputs) {
                string new_str = str.ToString();
                work_mtx.lock();
                if (work.count(new_str) == 0) {
                    fprintf(file, "[fatal]: child node done but parent haven't recorded yet\n");
                    work_mtx.unlock();
                    continue;
                }
                work_mtx.unlock();
                vertex *v_parent = addvertex(new_str);
                //no gap_mtx is needed here currently
                //v_parent->gap_mtx.lock();
                v_parent->minimum_gap = min(v->all_start_micros - v_parent->all_start_micros, v_parent->minimum_gap);
                //v_parent->gap_mtx.unlock();
            }
            fclose(file);
            log_mtx.unlock();
        }
    }
}
<commit_msg>added graph logger<commit_after>#include "tensorflow/core/common_runtime/GraphLogger.h"
#include "tensorflow/core/framework/step_stats.pb.h"
namespace tensorflow {

    vertex *GraphLogger::addvertex(const string &name)
    {
        mutex_lock l(work_mtx);
        if (work.count(name) == 0) {
            return new vertex(name);
        } else {
            cout << "\nVertex already exists!";
            return work[name];
        }
    }

    void GraphLogger::addedge(const string &from, const string &to, double cost)
    {
        vertex *f = addvertex(from);
        vertex *t = addvertex(to);
        pair<double, vertex *> edge = make_pair(cost, t);
        //f->adj_mtx.lock();
        //f->adj.push_back(edge);
        //f->adj_mtx.unlock();
        addadj(f, edge);
    }

    void GraphLogger::addadj(vertex *v, pair<double, vertex *> edge) {
        v->adj_mtx.lock();
        v->adj.push_back(edge);
        v->adj_mtx.unlock();
    }

    void GraphLogger::addnodes(string node_name) {
        mutex_lock l(recv_nodes_mtx);
        recv_nodes.push_back(node_name);
    }

    size_t GraphLogger::get_memory() {
        memory_mtx.lock();
        mutex_lock l(recv_nodes_mtx);
        memory += sizeof(work);
        memory += sizeof(recv_nodes);
        for (auto item : work) {
            item.second->adj_mtx.lock();
            memory += sizeof(*(item.second));
            item.second->adj_mtx.unlock();
        }
        size_t result = memory;
        memory_mtx.unlock();
        return result;
    }

    void GraphLogger::add_step_stats(NodeExecStats* nt, const Node *node)
    {
        if (nt) {
            log_mtx.lock();
            FILE *file = fopen("/tmp/step_stat.log", "a+");
            fprintf(file, "node_name: ");
            fprintf(file, nt->node_name().c_str());
            fprintf(file, "\n");

            fprintf(file, "all_start_micros: ");
            fprintf(file, "%ld", nt->all_start_micros());
            fprintf(file, "\n");

            fprintf(file, "op_start_rel_micros: ");
            fprintf(file, "%ld", nt->op_start_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "op_end_rel_micros: ");
            fprintf(file, "%ld", nt->op_end_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "all_end_rel_micros: ");
            fprintf(file, "%ld", nt->all_end_rel_micros());
            fprintf(file, "\n");

            fprintf(file, "scheduled_micros: ");
            fprintf(file, "%ld", nt->scheduled_micros());
            fprintf(file, "\n");

            fprintf(file, "schedule_start_skew: ");
            fprintf(file, "%ld", nt->all_start_micros()- nt->scheduled_micros());
            fprintf(file, "\n");

            fprintf(file, "thread_id: ");
            fprintf(file, "%ld", nt->thread_id());
            fprintf(file, "\n");

            fprintf(file, "timeline_label: ");
            fprintf(file, nt->timeline_label().c_str());
            fprintf(file, "\n");

            fprintf(file, "\n");
            fflush(file);

            // update the information
            vertex *v = addvertex(nt->node_name());
            v->all_start_micros = nt->all_start_micros();
            v->op_start_rel_micros = nt->op_start_rel_micros();
            v->op_end_rel_micros = nt->op_end_rel_micros();
            v->all_end_rel_micros = nt->all_end_rel_micros();
            //v->total_bytes = ;
            //v->peak_bytes;
            v->timeline_label = nt->timeline_label();
            v->scheduled_micros = nt->scheduled_micros();
            v->thread_id = nt->thread_id();

            // add informaion in node for
            // 1. sender inforamtion of receiver
            // 2. consum operation for receiver
            const NodeDef& def = node->def();
            if (IsRecv(node)) {
                string send_device;
                TF_CHECK_OK(GetNodeAttr(def, "send_device", &send_device));
                v->is_recv = true;
                v->sender = send_device;
                //currently no mutex lock is needed now
                //recv_nodes_mtx.lock();
                addnodes(nt->node_name());
                //recv_nodes_mtx.unlock();
            }
            std::vector<StringPiece> inputs = std::vector<StringPiece>(def.input().begin(), def.input().end());
            for (auto& str : inputs) {
                string new_str = str.ToString();
                work_mtx.lock();
                if (work.count(new_str) == 0) {
                    fprintf(file, "[fatal]: child node done but parent haven't recorded yet\n");
                    work_mtx.unlock();
                    continue;
                }
                work_mtx.unlock();
                vertex *v_parent = addvertex(new_str);
                //no gap_mtx is needed here currently
                //v_parent->gap_mtx.lock();
                v_parent->minimum_gap = min(v->all_start_micros - v_parent->all_start_micros, v_parent->minimum_gap);
                //v_parent->gap_mtx.unlock();
            }
            fclose(file);
            log_mtx.unlock();
        }
    }
}
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/profiler/internal/tfprof_op.h"

#include <stdio.h>
#include <utility>

#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/regexp.h"
#include "tensorflow/core/profiler/internal/tfprof_constants.h"
#include "tensorflow/core/profiler/internal/tfprof_tensor.h"

namespace tensorflow {
namespace tfprof {
namespace {
string FormatToalExecTime(const ShowMultiNode* node,
                          const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_exec_micros() /
               root->proto().total_exec_micros();
    pct =
        100.0 * node->proto().exec_micros() / root->proto().total_exec_micros();
  }

  return strings::Printf(
      "%30s", strings::Printf("%s (%.2f%%, %.2f%%)",
                              FormatTime(node->proto().exec_micros()).c_str(),
                              accu_pct, pct)
                  .c_str());
}
string FormatCPUExecTime(const ShowMultiNode* node, const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_cpu_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_cpu_exec_micros() /
               root->proto().total_cpu_exec_micros();
    pct = 100.0 * node->proto().cpu_exec_micros() /
          root->proto().total_cpu_exec_micros();
  }

  return strings::Printf(
      "%30s",
      strings::Printf("%s (%.2f%%, %.2f%%)",
                      FormatTime(node->proto().cpu_exec_micros()).c_str(),
                      accu_pct, pct)
          .c_str());
}
string FormatAcceleratorExecTime(const ShowMultiNode* node,
                                 const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_accelerator_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_accelerator_exec_micros() /
               root->proto().total_accelerator_exec_micros();
    pct = 100.0 * node->proto().accelerator_exec_micros() /
          root->proto().total_accelerator_exec_micros();
  }

  return strings::Printf(
      "%30s", strings::Printf(
                  "%s (%.2f%%, %.2f%%)",
                  FormatTime(node->proto().accelerator_exec_micros()).c_str(),
                  accu_pct, pct)
                  .c_str());
}
}  // namespace

void TFOp::AddNode(TFGraphNode* node) {
  const string& op = node->op();
  if (tfcnodes_map_.find(op) == tfcnodes_map_.end()) {
    tfcnodes_map_[op] =
        std::unique_ptr<TFMultiGraphNode>(new TFMultiGraphNode(op));
  }
  TFMultiGraphNode* tfcnode = tfcnodes_map_[op].get();
  tfcnode->AddGraphNode(node);
}

void TFOp::Build() {
  for (auto& tn : tfcnodes_map_) {
    cnodes_map_[tn.first] =
        std::unique_ptr<OpNode>(new OpNode(tn.second.get()));
  }

  tfcnodes_map_[kTFProfRoot] =
      std::unique_ptr<TFMultiGraphNode>(new TFMultiGraphNode(kTFProfRoot));
  root_.reset(new OpNode(tfcnodes_map_[kTFProfRoot].get()));
}

const ShowMultiNode* TFOp::ShowInternal(const Options& opts,
                                        Timeline* timeline) {
  root_->ResetTotalStats();
  if (opts.output_type == kOutput[3]) {
    fprintf(stderr, "Only 'code' view supports pprof output now.\n");
    return root_.get();
  }
  if (opts.output_type == kOutput[1] || opts.output_type == kOutput[2]) {
    root_->formatted_str = FormatNode(root_.get(), root_.get(), opts);
  }
  if (timeline) {
    fprintf(stderr,
            "op view doesn't support timeline yet. "
            "Consider graph/scope/code view.\n");
    return root_.get();
  }
  if (cnodes_map_.empty()) {
    return root_.get();
  }

  std::vector<OpNode*> nodes;
  for (auto& n : cnodes_map_) {
    n.second->account = ReAccount(n.second.get(), opts);
    n.second->ResetTotalStats();
    n.second->AddSelfToTotalStats();
    nodes.push_back(n.second.get());
  }
  nodes = SortNodes(nodes, opts);
  // pre keeps track of previous visited node.
  OpNode* pre = nullptr;
  std::vector<OpNode*> account_nodes;
  for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
    if ((*it)->account) {
      if (pre) (*it)->AggregateTotalStats(pre);
      account_nodes.push_back(*it);
      pre = *it;
    }
  }
  std::reverse(std::begin(account_nodes), std::end(account_nodes));
  if (pre) {
    root_->AggregateTotalStats(pre);
  }

  // Perform the display and optionally redo accounting.
  int64 depth = 0;
  std::vector<OpNode*> show_nodes;
  int64 start = SearchRoot(account_nodes, opts.start_name_regexes);
  for (int64 i = start; i < account_nodes.size(); ++i, ++depth) {
    OpNode* n = account_nodes[i];
    if (ShouldTrim(n, opts.trim_name_regexes) || depth > opts.max_depth) {
      break;
    }
    n->show = ShouldShow(n, opts, depth);
    if (n->show) show_nodes.push_back(n);
  }

  pre = nullptr;
  for (auto it = show_nodes.rbegin(); it != show_nodes.rend(); ++it) {
    if (opts.account_displayed_op_only) {
      (*it)->ResetTotalStats();
      (*it)->AddSelfToTotalStats();
      if (pre) (*it)->AggregateTotalStats(pre);
    }
    pre = *it;
  }
  if (opts.account_displayed_op_only) {
    root_->ResetTotalStats();
    if (pre) {
      root_->AggregateTotalStats(pre);
    }
  }
  if (opts.output_type == kOutput[1] || opts.output_type == kOutput[2]) {
    string display_str = FormatLegend(opts);
    for (OpNode* node : show_nodes) {
      display_str += FormatNode(node, root_.get(), opts);
    }
    // In op view, we don't show root (total). But it will still in proto.
    // TODO(xpan): Is it the right choice?
    root_->formatted_str = display_str;
  }
  // Populate the chidren field.
  auto* pre_pb = root_->mutable_proto();
  for (auto& show_node : show_nodes) {
    pre_pb->clear_children();
    pre_pb->add_children()->Swap(show_node->mutable_proto());
    pre_pb = pre_pb->mutable_children(0);
  }
  return root_.get();
}

int64 TFOp::SearchRoot(const std::vector<OpNode*> nodes,
                       const std::vector<string>& regexes) {
  if (regexes.empty() || (regexes.size() == 1 && regexes[0] == ".*")) {
    return 0;
  }
  int64 i = 0;
  for (; i < nodes.size(); ++i) {
    for (const string& regex : regexes) {
      if (RE2::FullMatch(nodes[i]->name(), regex)) {
        return i;
      }
    }
  }
  return i;
}

string TFOp::FormatMemoryNode(int64 node_total_bytes, int64 root_total_bytes,
                              int64 node_bytes) const {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node_bytes > 0) {
    accu_pct = 100.0 * node_total_bytes / root_total_bytes;
    pct = 100.0 * node_bytes / root_total_bytes;
  }
  return strings::Printf(
      "%30s", strings::Printf("%s (%.2f%%, %.2f%%)",
                              FormatMemory(node_bytes).c_str(), accu_pct, pct)
                  .c_str());
}

string TFOp::FormatNode(OpNode* node, OpNode* root, const Options& opts) const {
  std::vector<string> attrs;

  if (opts.select.find(kShown[0]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_requested_bytes(),
                                     root->proto().total_requested_bytes(),
                                     node->proto().requested_bytes()));
  }

  if (opts.select.find(kShown[11]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_peak_bytes(),
                                     root->proto().total_peak_bytes(),
                                     node->proto().peak_bytes()));
  }

  if (opts.select.find(kShown[12]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_residual_bytes(),
                                     root->proto().total_residual_bytes(),
                                     node->proto().residual_bytes()));
  }
  if (opts.select.find(kShown[13]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_output_bytes(),
                                     root->proto().total_output_bytes(),
                                     node->proto().output_bytes()));
  }

  if (opts.select.find(kShown[1]) != opts.select.end()) {
    attrs.push_back(FormatToalExecTime(node, root));
    attrs.push_back(FormatAcceleratorExecTime(node, root));
    attrs.push_back(FormatCPUExecTime(node, root));
  }
  if (opts.select.find(kShown[9]) != opts.select.end() &&
      opts.select.find(kShown[1]) == opts.select.end()) {
    attrs.push_back(FormatAcceleratorExecTime(node, root));
  }
  if (opts.select.find(kShown[10]) != opts.select.end() &&
      opts.select.find(kShown[1]) == opts.select.end()) {
    attrs.push_back(FormatCPUExecTime(node, root));
  }
  if (opts.select.find(kShown[2]) != opts.select.end()) {
    double accu_pct = 0.0;
    double pct = 0.0;
    if (node->proto().total_parameters() > 0) {
      accu_pct = 100.0 * node->proto().total_parameters() /
                 root->proto().total_parameters();
      pct =
          100.0 * node->proto().parameters() / root->proto().total_parameters();
    }
    attrs.push_back(strings::Printf(
        "%30s",
        strings::Printf("%s params (%.2f%%, %.2f%%)",
                        FormatNumber(node->proto().parameters()).c_str(),
                        accu_pct, pct)
            .c_str()));
  }

  if (opts.select.find(kShown[3]) != opts.select.end()) {
    double accu_pct = 0.0;
    double pct = 0.0;
    if (node->proto().total_float_ops() > 0) {
      accu_pct = 100.0 * node->proto().total_float_ops() /
                 root->proto().total_float_ops();
      pct = 100.0 * node->proto().float_ops() / root->proto().total_float_ops();
    }

    attrs.push_back(strings::Printf(
        "%30s", strings::Printf("%s float_ops (%.2f%%, %.2f%%)",
                                FormatNumber(node->proto().float_ops()).c_str(),
                                accu_pct, pct)
                    .c_str()));
  }

  if (opts.select.find(kShown[5]) != opts.select.end()) {
    attrs.push_back(str_util::Join(node->node->devices(), "|"));
  }

  if (opts.select.find(kShown[6]) != opts.select.end()) {
    std::set<string> op_types = node->node->op_types();
    attrs.push_back(str_util::Join(op_types, "|"));
  }

  if (opts.select.find(kShown[7]) != opts.select.end()) {
    int64 total_runs = 0;
    for (const auto& gnode : node->proto().graph_nodes()) {
      total_runs += gnode.run_count();
    }
    attrs.push_back(strings::Printf(
        "%10s",
        strings::Printf("%lld|%d", total_runs, node->proto().graph_nodes_size())
            .c_str()));
  }

  string node_str = strings::Printf("%-25s%s\n", node->name().c_str(),
                                    str_util::Join(attrs, ", ").c_str());

  if (opts.select.find(kShown[8]) != opts.select.end()) {
    string input_shape_str = FormatInputShapes(node->proto());
    if (!input_shape_str.empty()) {
      node_str = strings::Printf("%s\n%s\n\n", node_str.c_str(),
                                 input_shape_str.c_str());
    }
  }
  return node_str;
}
}  // namespace tfprof
}  // namespace tensorflow
<commit_msg>Fixed typo<commit_after>/* Copyright 2016 The TensorFlow Authors All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/profiler/internal/tfprof_op.h"

#include <stdio.h>
#include <utility>

#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/regexp.h"
#include "tensorflow/core/profiler/internal/tfprof_constants.h"
#include "tensorflow/core/profiler/internal/tfprof_tensor.h"

namespace tensorflow {
namespace tfprof {
namespace {
string FormatToalExecTime(const ShowMultiNode* node,
                          const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_exec_micros() /
               root->proto().total_exec_micros();
    pct =
        100.0 * node->proto().exec_micros() / root->proto().total_exec_micros();
  }

  return strings::Printf(
      "%30s", strings::Printf("%s (%.2f%%, %.2f%%)",
                              FormatTime(node->proto().exec_micros()).c_str(),
                              accu_pct, pct)
                  .c_str());
}
string FormatCPUExecTime(const ShowMultiNode* node, const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_cpu_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_cpu_exec_micros() /
               root->proto().total_cpu_exec_micros();
    pct = 100.0 * node->proto().cpu_exec_micros() /
          root->proto().total_cpu_exec_micros();
  }

  return strings::Printf(
      "%30s",
      strings::Printf("%s (%.2f%%, %.2f%%)",
                      FormatTime(node->proto().cpu_exec_micros()).c_str(),
                      accu_pct, pct)
          .c_str());
}
string FormatAcceleratorExecTime(const ShowMultiNode* node,
                                 const ShowMultiNode* root) {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node->proto().total_accelerator_exec_micros() > 0) {
    accu_pct = 100.0 * node->proto().total_accelerator_exec_micros() /
               root->proto().total_accelerator_exec_micros();
    pct = 100.0 * node->proto().accelerator_exec_micros() /
          root->proto().total_accelerator_exec_micros();
  }

  return strings::Printf(
      "%30s", strings::Printf(
                  "%s (%.2f%%, %.2f%%)",
                  FormatTime(node->proto().accelerator_exec_micros()).c_str(),
                  accu_pct, pct)
                  .c_str());
}
}  // namespace

void TFOp::AddNode(TFGraphNode* node) {
  const string& op = node->op();
  if (tfcnodes_map_.find(op) == tfcnodes_map_.end()) {
    tfcnodes_map_[op] =
        std::unique_ptr<TFMultiGraphNode>(new TFMultiGraphNode(op));
  }
  TFMultiGraphNode* tfcnode = tfcnodes_map_[op].get();
  tfcnode->AddGraphNode(node);
}

void TFOp::Build() {
  for (auto& tn : tfcnodes_map_) {
    cnodes_map_[tn.first] =
        std::unique_ptr<OpNode>(new OpNode(tn.second.get()));
  }

  tfcnodes_map_[kTFProfRoot] =
      std::unique_ptr<TFMultiGraphNode>(new TFMultiGraphNode(kTFProfRoot));
  root_.reset(new OpNode(tfcnodes_map_[kTFProfRoot].get()));
}

const ShowMultiNode* TFOp::ShowInternal(const Options& opts,
                                        Timeline* timeline) {
  root_->ResetTotalStats();
  if (opts.output_type == kOutput[3]) {
    fprintf(stderr, "Only 'code' view supports pprof output now.\n");
    return root_.get();
  }
  if (opts.output_type == kOutput[1] || opts.output_type == kOutput[2]) {
    root_->formatted_str = FormatNode(root_.get(), root_.get(), opts);
  }
  if (timeline) {
    fprintf(stderr,
            "op view doesn't support timeline yet. "
            "Consider graph/scope/code view.\n");
    return root_.get();
  }
  if (cnodes_map_.empty()) {
    return root_.get();
  }

  std::vector<OpNode*> nodes;
  for (auto& n : cnodes_map_) {
    n.second->account = ReAccount(n.second.get(), opts);
    n.second->ResetTotalStats();
    n.second->AddSelfToTotalStats();
    nodes.push_back(n.second.get());
  }
  nodes = SortNodes(nodes, opts);
  // pre keeps track of previous visited node.
  OpNode* pre = nullptr;
  std::vector<OpNode*> account_nodes;
  for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
    if ((*it)->account) {
      if (pre) (*it)->AggregateTotalStats(pre);
      account_nodes.push_back(*it);
      pre = *it;
    }
  }
  std::reverse(std::begin(account_nodes), std::end(account_nodes));
  if (pre) {
    root_->AggregateTotalStats(pre);
  }

  // Perform the display and optionally redo accounting.
  int64 depth = 0;
  std::vector<OpNode*> show_nodes;
  int64 start = SearchRoot(account_nodes, opts.start_name_regexes);
  for (int64 i = start; i < account_nodes.size(); ++i, ++depth) {
    OpNode* n = account_nodes[i];
    if (ShouldTrim(n, opts.trim_name_regexes) || depth > opts.max_depth) {
      break;
    }
    n->show = ShouldShow(n, opts, depth);
    if (n->show) show_nodes.push_back(n);
  }

  pre = nullptr;
  for (auto it = show_nodes.rbegin(); it != show_nodes.rend(); ++it) {
    if (opts.account_displayed_op_only) {
      (*it)->ResetTotalStats();
      (*it)->AddSelfToTotalStats();
      if (pre) (*it)->AggregateTotalStats(pre);
    }
    pre = *it;
  }
  if (opts.account_displayed_op_only) {
    root_->ResetTotalStats();
    if (pre) {
      root_->AggregateTotalStats(pre);
    }
  }
  if (opts.output_type == kOutput[1] || opts.output_type == kOutput[2]) {
    string display_str = FormatLegend(opts);
    for (OpNode* node : show_nodes) {
      display_str += FormatNode(node, root_.get(), opts);
    }
    // In op view, we don't show root (total). But it will still in proto.
    // TODO(xpan): Is it the right choice?
    root_->formatted_str = display_str;
  }
  // Populate the children field.
  auto* pre_pb = root_->mutable_proto();
  for (auto& show_node : show_nodes) {
    pre_pb->clear_children();
    pre_pb->add_children()->Swap(show_node->mutable_proto());
    pre_pb = pre_pb->mutable_children(0);
  }
  return root_.get();
}

int64 TFOp::SearchRoot(const std::vector<OpNode*> nodes,
                       const std::vector<string>& regexes) {
  if (regexes.empty() || (regexes.size() == 1 && regexes[0] == ".*")) {
    return 0;
  }
  int64 i = 0;
  for (; i < nodes.size(); ++i) {
    for (const string& regex : regexes) {
      if (RE2::FullMatch(nodes[i]->name(), regex)) {
        return i;
      }
    }
  }
  return i;
}

string TFOp::FormatMemoryNode(int64 node_total_bytes, int64 root_total_bytes,
                              int64 node_bytes) const {
  double accu_pct = 0.0;
  double pct = 0.0;
  if (node_bytes > 0) {
    accu_pct = 100.0 * node_total_bytes / root_total_bytes;
    pct = 100.0 * node_bytes / root_total_bytes;
  }
  return strings::Printf(
      "%30s", strings::Printf("%s (%.2f%%, %.2f%%)",
                              FormatMemory(node_bytes).c_str(), accu_pct, pct)
                  .c_str());
}

string TFOp::FormatNode(OpNode* node, OpNode* root, const Options& opts) const {
  std::vector<string> attrs;

  if (opts.select.find(kShown[0]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_requested_bytes(),
                                     root->proto().total_requested_bytes(),
                                     node->proto().requested_bytes()));
  }

  if (opts.select.find(kShown[11]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_peak_bytes(),
                                     root->proto().total_peak_bytes(),
                                     node->proto().peak_bytes()));
  }

  if (opts.select.find(kShown[12]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_residual_bytes(),
                                     root->proto().total_residual_bytes(),
                                     node->proto().residual_bytes()));
  }
  if (opts.select.find(kShown[13]) != opts.select.end()) {
    attrs.push_back(FormatMemoryNode(node->proto().total_output_bytes(),
                                     root->proto().total_output_bytes(),
                                     node->proto().output_bytes()));
  }

  if (opts.select.find(kShown[1]) != opts.select.end()) {
    attrs.push_back(FormatToalExecTime(node, root));
    attrs.push_back(FormatAcceleratorExecTime(node, root));
    attrs.push_back(FormatCPUExecTime(node, root));
  }
  if (opts.select.find(kShown[9]) != opts.select.end() &&
      opts.select.find(kShown[1]) == opts.select.end()) {
    attrs.push_back(FormatAcceleratorExecTime(node, root));
  }
  if (opts.select.find(kShown[10]) != opts.select.end() &&
      opts.select.find(kShown[1]) == opts.select.end()) {
    attrs.push_back(FormatCPUExecTime(node, root));
  }
  if (opts.select.find(kShown[2]) != opts.select.end()) {
    double accu_pct = 0.0;
    double pct = 0.0;
    if (node->proto().total_parameters() > 0) {
      accu_pct = 100.0 * node->proto().total_parameters() /
                 root->proto().total_parameters();
      pct =
          100.0 * node->proto().parameters() / root->proto().total_parameters();
    }
    attrs.push_back(strings::Printf(
        "%30s",
        strings::Printf("%s params (%.2f%%, %.2f%%)",
                        FormatNumber(node->proto().parameters()).c_str(),
                        accu_pct, pct)
            .c_str()));
  }

  if (opts.select.find(kShown[3]) != opts.select.end()) {
    double accu_pct = 0.0;
    double pct = 0.0;
    if (node->proto().total_float_ops() > 0) {
      accu_pct = 100.0 * node->proto().total_float_ops() /
                 root->proto().total_float_ops();
      pct = 100.0 * node->proto().float_ops() / root->proto().total_float_ops();
    }

    attrs.push_back(strings::Printf(
        "%30s", strings::Printf("%s float_ops (%.2f%%, %.2f%%)",
                                FormatNumber(node->proto().float_ops()).c_str(),
                                accu_pct, pct)
                    .c_str()));
  }

  if (opts.select.find(kShown[5]) != opts.select.end()) {
    attrs.push_back(str_util::Join(node->node->devices(), "|"));
  }

  if (opts.select.find(kShown[6]) != opts.select.end()) {
    std::set<string> op_types = node->node->op_types();
    attrs.push_back(str_util::Join(op_types, "|"));
  }

  if (opts.select.find(kShown[7]) != opts.select.end()) {
    int64 total_runs = 0;
    for (const auto& gnode : node->proto().graph_nodes()) {
      total_runs += gnode.run_count();
    }
    attrs.push_back(strings::Printf(
        "%10s",
        strings::Printf("%lld|%d", total_runs, node->proto().graph_nodes_size())
            .c_str()));
  }

  string node_str = strings::Printf("%-25s%s\n", node->name().c_str(),
                                    str_util::Join(attrs, ", ").c_str());

  if (opts.select.find(kShown[8]) != opts.select.end()) {
    string input_shape_str = FormatInputShapes(node->proto());
    if (!input_shape_str.empty()) {
      node_str = strings::Printf("%s\n%s\n\n", node_str.c_str(),
                                 input_shape_str.c_str());
    }
  }
  return node_str;
}
}  // namespace tfprof
}  // namespace tensorflow
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Ping.hxx"
#include "system/Error.hxx"
#include "net/IPv4Address.hxx"
#include "net/SocketAddress.hxx"
#include "net/SendMessage.hxx"
#include "event/Duration.hxx"

#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

PingClient::PingClient(EventLoop &event_loop, PingClientHandler &_handler)
    :event(event_loop, -1, 0, BIND_THIS_METHOD(EventCallback)),
     handler(_handler)
{
}

inline void
PingClient::ScheduleRead()
{
    event.Add(EventDuration<10>::value);
}

static u_short
in_cksum(const u_short *addr, register int len, u_short csum)
{
	int nleft = len;
	const u_short *w = addr;
	u_short answer;
	int sum = csum;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nleft == 1)
		sum += htons(*(const u_char *)w << 8);

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}

static bool
parse_reply(struct msghdr *msg, size_t cc, uint16_t ident)
{
    const void *buf = (const void *)msg->msg_iov->iov_base;
    const struct icmphdr *icp = (const struct icmphdr *)buf;
    if (cc < sizeof(*icp))
        return false;

    return icp->type == ICMP_ECHOREPLY && icp->un.echo.id == ident;
}

inline void
PingClient::Read()
{
    char buffer[1024];
    struct iovec iov = {
        .iov_base = buffer,
        .iov_len = sizeof(buffer),
    };

    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));

    char addrbuf[128];
    msg.msg_name = addrbuf;
    msg.msg_namelen = sizeof(addrbuf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    char ans_data[4096];
    msg.msg_control = ans_data;
    msg.msg_controllen = sizeof(ans_data);

    int cc = recvmsg(fd.Get(), &msg, MSG_DONTWAIT);
    if (cc >= 0) {
        if (parse_reply(&msg, cc, ident)) {
            fd.Close();
            handler.PingResponse();
        } else
            ScheduleRead();
    } else if (errno == EAGAIN || errno == EINTR) {
        ScheduleRead();
    } else {
        const int e = errno;
        fd.Close();
        handler.PingError(std::make_exception_ptr(MakeErrno(e)));
    }
}

/*
 * libevent callback
 *
 */

inline void
PingClient::EventCallback(unsigned events)
{
    assert(fd.IsDefined());

    if (events & SocketEvent::READ) {
        Read();
    } else {
        fd.Close();
        handler.PingTimeout();
    }
}

/*
 * constructor
 *
 */

bool
ping_available(void)
{
    int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    if (fd < 0)
        return false;
    close(fd);
    return true;
}

static UniqueSocketDescriptor
CreateIcmp()
{
    UniqueSocketDescriptor fd;
    if (!fd.CreateNonBlock(AF_INET, SOCK_DGRAM, IPPROTO_ICMP))
        throw MakeErrno("Failed to create ICMP socket");

    return fd;
}

static uint16_t
MakeIdent(SocketDescriptor fd)
{
    if (!fd.Bind(IPv4Address(0)))
        throw MakeErrno("Failed to bind ICMP socket");

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    socklen_t sin_length = sizeof(sin);

    if (getsockname(fd.Get(), (struct sockaddr *)&sin, &sin_length) < 0)
        throw MakeErrno("Failed to inspect ICMP socket");

    return sin.sin_port;
}

static void
SendPing(SocketDescriptor fd, SocketAddress address, uint16_t ident)
{
    struct {
        struct icmphdr header;
        char data[8];
    } packet;

    packet.header.type = ICMP_ECHO;
    packet.header.code = 0;
    packet.header.checksum = 0;
    packet.header.un.echo.sequence = htons(1);
    packet.header.un.echo.id = ident;
    memset(packet.data, 0, sizeof(packet.data));
    packet.header.checksum = in_cksum((u_short *)&packet, sizeof(packet), 0);

    struct iovec iov = {
        .iov_base = &packet,
        .iov_len = sizeof(packet),
    };

    SendMessage(fd,
                MessageHeader(ConstBuffer<struct iovec>(&iov, 1))
                .SetAddress(address), 0);
}

void
PingClient::Start(SocketAddress address)
{
    try {
        fd = CreateIcmp();
        ident = MakeIdent(fd);
        SendPing(fd, address, ident);
    } catch (...) {
        handler.PingError(std::current_exception());
        return;
    }

    ScheduleRead();
}
<commit_msg>net/Ping: remove deprecated `register` keyword<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Ping.hxx"
#include "system/Error.hxx"
#include "net/IPv4Address.hxx"
#include "net/SocketAddress.hxx"
#include "net/SendMessage.hxx"
#include "event/Duration.hxx"

#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

PingClient::PingClient(EventLoop &event_loop, PingClientHandler &_handler)
    :event(event_loop, -1, 0, BIND_THIS_METHOD(EventCallback)),
     handler(_handler)
{
}

inline void
PingClient::ScheduleRead()
{
    event.Add(EventDuration<10>::value);
}

static u_short
in_cksum(const u_short *addr, int len, u_short csum)
{
	int nleft = len;
	const u_short *w = addr;
	u_short answer;
	int sum = csum;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nleft == 1)
		sum += htons(*(const u_char *)w << 8);

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}

static bool
parse_reply(struct msghdr *msg, size_t cc, uint16_t ident)
{
    const void *buf = (const void *)msg->msg_iov->iov_base;
    const struct icmphdr *icp = (const struct icmphdr *)buf;
    if (cc < sizeof(*icp))
        return false;

    return icp->type == ICMP_ECHOREPLY && icp->un.echo.id == ident;
}

inline void
PingClient::Read()
{
    char buffer[1024];
    struct iovec iov = {
        .iov_base = buffer,
        .iov_len = sizeof(buffer),
    };

    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));

    char addrbuf[128];
    msg.msg_name = addrbuf;
    msg.msg_namelen = sizeof(addrbuf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    char ans_data[4096];
    msg.msg_control = ans_data;
    msg.msg_controllen = sizeof(ans_data);

    int cc = recvmsg(fd.Get(), &msg, MSG_DONTWAIT);
    if (cc >= 0) {
        if (parse_reply(&msg, cc, ident)) {
            fd.Close();
            handler.PingResponse();
        } else
            ScheduleRead();
    } else if (errno == EAGAIN || errno == EINTR) {
        ScheduleRead();
    } else {
        const int e = errno;
        fd.Close();
        handler.PingError(std::make_exception_ptr(MakeErrno(e)));
    }
}

/*
 * libevent callback
 *
 */

inline void
PingClient::EventCallback(unsigned events)
{
    assert(fd.IsDefined());

    if (events & SocketEvent::READ) {
        Read();
    } else {
        fd.Close();
        handler.PingTimeout();
    }
}

/*
 * constructor
 *
 */

bool
ping_available(void)
{
    int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    if (fd < 0)
        return false;
    close(fd);
    return true;
}

static UniqueSocketDescriptor
CreateIcmp()
{
    UniqueSocketDescriptor fd;
    if (!fd.CreateNonBlock(AF_INET, SOCK_DGRAM, IPPROTO_ICMP))
        throw MakeErrno("Failed to create ICMP socket");

    return fd;
}

static uint16_t
MakeIdent(SocketDescriptor fd)
{
    if (!fd.Bind(IPv4Address(0)))
        throw MakeErrno("Failed to bind ICMP socket");

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    socklen_t sin_length = sizeof(sin);

    if (getsockname(fd.Get(), (struct sockaddr *)&sin, &sin_length) < 0)
        throw MakeErrno("Failed to inspect ICMP socket");

    return sin.sin_port;
}

static void
SendPing(SocketDescriptor fd, SocketAddress address, uint16_t ident)
{
    struct {
        struct icmphdr header;
        char data[8];
    } packet;

    packet.header.type = ICMP_ECHO;
    packet.header.code = 0;
    packet.header.checksum = 0;
    packet.header.un.echo.sequence = htons(1);
    packet.header.un.echo.id = ident;
    memset(packet.data, 0, sizeof(packet.data));
    packet.header.checksum = in_cksum((u_short *)&packet, sizeof(packet), 0);

    struct iovec iov = {
        .iov_base = &packet,
        .iov_len = sizeof(packet),
    };

    SendMessage(fd,
                MessageHeader(ConstBuffer<struct iovec>(&iov, 1))
                .SetAddress(address), 0);
}

void
PingClient::Start(SocketAddress address)
{
    try {
        fd = CreateIcmp();
        ident = MakeIdent(fd);
        SendPing(fd, address, ident);
    } catch (...) {
        handler.PingError(std::current_exception());
        return;
    }

    ScheduleRead();
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
// todo make this turn off for .net
#if defined(_MSC_VER)
  #pragma warning(disable: 4786)
#endif

#include <string.h>
#include <math.h>
#include <ctype.h>
#include <fstream>
#include "common.h"
#include "global.h"
#include "Ping.h"
#include "Protocol.h"
#include "TimeKeeper.h"
#include "bzfio.h"

// incessint rebuilding for current versioning
#include "version.h"

//
// PingPacket
//

const int		PingPacket::PacketSize = ServerIdPLen + 52;

PingPacket::PingPacket() : gameStyle(PlainGameStyle),
				maxShots(1),
				shakeWins(0),
				shakeTimeout(0),
				maxPlayerScore(0),
				maxTeamScore(0),
				maxTime(0),
				maxPlayers(1),
				rogueCount(0),
				rogueMax(1),
				redCount(0),
				redMax(1),
				greenCount(0),
				greenMax(1),
				blueCount(0),
				blueMax(1),
				purpleCount(0),
				purpleMax(1),
				observerCount(0),
				observerMax(1)
{
  // do nothing
}

PingPacket::~PingPacket()
{
  // do nothing
}

bool			PingPacket::read(int fd, struct sockaddr_in* addr)
{
  char buffer[PacketSize], serverVersion[9];
  uint16_t len, code;

  // get packet
  int n = recvMulticast(fd, buffer, sizeof(buffer), addr);
  if (n < 4)
    return false;

  // decode header
  void* buf = buffer;
  buf = nboUnpackUShort(buf, len);
  buf = nboUnpackUShort(buf, code);

  // make sure we got the rest of the message
  if (len != n - 4)
    return false;

  // check that it's a reply
  if (code != MsgPingCodeReply)
    return false;

  // unpack body of reply
  buf = unpack(buf, serverVersion);

  // compare protocol version against my protocol version.
  return (strcmp(serverVersion, getServerVersion()) == 0);
}

bool			PingPacket::waitForReply(int fd,
				const Address& from,
				int millisecondsToBlock)
{
  // block waiting on input.  if the incoming message is not from the
  // indicated source then ignore it and go back to waiting.  if the
  // incoming message is not a ping then ignore it and go back to waiting.
  float blockTime = 0.0001f * (float)millisecondsToBlock;
  TimeKeeper startTime = TimeKeeper::getCurrent();
  TimeKeeper currentTime = startTime;
  do {
    // prepare timeout
    const float timeLeft = blockTime - (currentTime - startTime);
    struct timeval timeout;
    timeout.tv_sec = long(floorf(timeLeft));
    timeout.tv_usec = long(1.0e+6f * (timeLeft - floorf(timeLeft)));

    // wait for input
    fd_set read_set;
    FD_ZERO(&read_set);
    _FD_SET(fd, &read_set);
    int nfound = select(fd+1, (fd_set*)&read_set, NULL, NULL, &timeout);

    // if got a message read it.  if a ping packet and from right
    // sender then return success.
    if (nfound < 0)
      return false;
    if (nfound > 0 && read(fd, NULL))
      if (sourceAddr == from)
	return true;

    currentTime = TimeKeeper::getCurrent();
  } while (currentTime - startTime < blockTime);
  return false;
}

bool			PingPacket::write(int fd,
					const struct sockaddr_in* addr) const
{
  char buffer[PacketSize] = {0};
  void* buf = buffer;
  buf = nboPackUShort(buf, PacketSize - 4);
  buf = nboPackUShort(buf, MsgPingCodeReply);
  buf = pack(buf, getServerVersion());
  return sendMulticast(fd, buffer, sizeof(buffer), addr) == sizeof(buffer);
}

bool			PingPacket::isRequest(int fd,
				struct sockaddr_in* addr)
{
  if (fd < 0) return false;
  char buffer[6];
  void *msg = buffer;
  uint16_t len, code;
  int size = recvMulticast(fd, buffer, sizeof(buffer), addr);
  if (size < 2) return false;
  msg = nboUnpackUShort(msg, len);
  msg = nboUnpackUShort(msg, code);
  return code == MsgPingCodeRequest;
}

bool			PingPacket::sendRequest(int fd,
					const struct sockaddr_in* addr)
{
  if (fd < 0 || !addr) return false;
  char buffer[6];
  void *msg = buffer;
  msg = nboPackUShort(msg, 2);
  msg = nboPackUShort(msg, MsgPingCodeRequest);
  msg = nboPackUShort(msg, (uint16_t) 0);
  return sendMulticast(fd, buffer, sizeof(buffer), addr) == sizeof(buffer);
}

void*			PingPacket::unpack(void* buf, char* version)
{
  buf = nboUnpackString(buf, version, 8);
  buf = serverId.unpack(buf);
  buf = sourceAddr.unpack(buf);
  buf = nboUnpackUShort(buf, gameStyle);
  buf = nboUnpackUShort(buf, maxShots);
  buf = nboUnpackUShort(buf, shakeWins);
  buf = nboUnpackUShort(buf, shakeTimeout);
  buf = nboUnpackUShort(buf, maxPlayerScore);
  buf = nboUnpackUShort(buf, maxTeamScore);
  buf = nboUnpackUShort(buf, maxTime);
  buf = nboUnpackUByte(buf, maxPlayers);
  buf = nboUnpackUByte(buf, rogueCount);
  buf = nboUnpackUByte(buf, rogueMax);
  buf = nboUnpackUByte(buf, redCount);
  buf = nboUnpackUByte(buf, redMax);
  buf = nboUnpackUByte(buf, greenCount);
  buf = nboUnpackUByte(buf, greenMax);
  buf = nboUnpackUByte(buf, blueCount);
  buf = nboUnpackUByte(buf, blueMax);
  buf = nboUnpackUByte(buf, purpleCount);
  buf = nboUnpackUByte(buf, purpleMax);
  buf = nboUnpackUByte(buf, observerCount);
  buf = nboUnpackUByte(buf, observerMax);
  return buf;
}

void*			PingPacket::pack(void* buf, const char* version) const
{
  buf = nboPackString(buf, version, 8);
  buf = serverId.pack(buf);
  buf = sourceAddr.pack(buf);
  buf = nboPackUShort(buf, gameStyle);
  buf = nboPackUShort(buf, maxShots);
  buf = nboPackUShort(buf, shakeWins);
  buf = nboPackUShort(buf, shakeTimeout);	// 1/10ths of second
  buf = nboPackUShort(buf, maxPlayerScore);
  buf = nboPackUShort(buf, maxTeamScore);
  buf = nboPackUShort(buf, maxTime);
  buf = nboPackUByte(buf, maxPlayers);
  buf = nboPackUByte(buf, rogueCount);
  buf = nboPackUByte(buf, rogueMax);
  buf = nboPackUByte(buf, redCount);
  buf = nboPackUByte(buf, redMax);
  buf = nboPackUByte(buf, greenCount);
  buf = nboPackUByte(buf, greenMax);
  buf = nboPackUByte(buf, blueCount);
  buf = nboPackUByte(buf, blueMax);
  buf = nboPackUByte(buf, purpleCount);
  buf = nboPackUByte(buf, purpleMax);
  buf = nboPackUByte(buf, observerCount);
  buf = nboPackUByte(buf, observerMax);
  return buf;
}

void			PingPacket::packHex(char* buf) const
{
  buf = packHex16(buf, gameStyle);
  buf = packHex16(buf, maxShots);
  buf = packHex16(buf, shakeWins);
  buf = packHex16(buf, shakeTimeout);
  buf = packHex16(buf, maxPlayerScore);
  buf = packHex16(buf, maxTeamScore);
  buf = packHex16(buf, maxTime);
  buf = packHex8(buf, maxPlayers);
  buf = packHex8(buf, rogueCount);
  buf = packHex8(buf, rogueMax);
  buf = packHex8(buf, redCount);
  buf = packHex8(buf, redMax);
  buf = packHex8(buf, greenCount);
  buf = packHex8(buf, greenMax);
  buf = packHex8(buf, blueCount);
  buf = packHex8(buf, blueMax);
  buf = packHex8(buf, purpleCount);
  buf = packHex8(buf, purpleMax);
  buf = packHex8(buf, observerCount);
  buf = packHex8(buf, observerMax);
  *buf = 0;
}

void			PingPacket::unpackHex(char* buf)
{
  buf = unpackHex16(buf, gameStyle);
  buf = unpackHex16(buf, maxShots);
  buf = unpackHex16(buf, shakeWins);
  buf = unpackHex16(buf, shakeTimeout);
  buf = unpackHex16(buf, maxPlayerScore);
  buf = unpackHex16(buf, maxTeamScore);
  buf = unpackHex16(buf, maxTime);
  buf = unpackHex8(buf, maxPlayers);
  buf = unpackHex8(buf, rogueCount);
  buf = unpackHex8(buf, rogueMax);
  buf = unpackHex8(buf, redCount);
  buf = unpackHex8(buf, redMax);
  buf = unpackHex8(buf, greenCount);
  buf = unpackHex8(buf, greenMax);
  buf = unpackHex8(buf, blueCount);
  buf = unpackHex8(buf, blueMax);
  buf = unpackHex8(buf, purpleCount);
  buf = unpackHex8(buf, purpleMax);
  buf = unpackHex8(buf, observerCount);
  buf = unpackHex8(buf, observerMax);
}

int			PingPacket::hex2bin(char d)
{
  switch (d) {
    case '0': return 0;
    case '1': return 1;
    case '2': return 2;
    case '3': return 3;
    case '4': return 4;
    case '5': return 5;
    case '6': return 6;
    case '7': return 7;
    case '8': return 8;
    case '9': return 9;
    case 'A':
    case 'a': return 10;
    case 'B':
    case 'b': return 11;
    case 'C':
    case 'c': return 12;
    case 'D':
    case 'd': return 13;
    case 'E':
    case 'e': return 14;
    case 'F':
    case 'f': return 15;
  }
  return 0;
}

char			PingPacket::bin2hex(int d)
{
  static const char* digit = "0123456789abcdef";
  return digit[d];
}

char*			PingPacket::packHex16(char* buf, uint16_t v)
{
  *buf++ = bin2hex((v >> 12) & 0xf);
  *buf++ = bin2hex((v >>  8) & 0xf);
  *buf++ = bin2hex((v >>  4) & 0xf);
  *buf++ = bin2hex( v        & 0xf);
  return buf;
}

char*			PingPacket::unpackHex16(char* buf, uint16_t& v)
{
  uint16_t d = 0;
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  v = d;
  return buf;
}

char*			PingPacket::packHex8(char* buf, uint8_t v)
{
  *buf++ = bin2hex((v >>  4) & 0xf);
  *buf++ = bin2hex( v        & 0xf);
  return buf;
}

char*			PingPacket::unpackHex8(char* buf, uint8_t& v)
{
  uint16_t d = 0;
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  v = (uint8_t)d;
  return buf;
}

void			 PingPacket::zeroPlayerCounts()
{
  rogueCount = 0;
  redCount = 0;
  greenCount = 0;
  blueCount = 0;
  purpleCount = 0;
  observerCount = 0;
}

// serialize packet to file -- note lack of error checking
// must write to a binary file if we use plain "pack"
void			 PingPacket::writeToFile (std::ostream& out) const
{
  if (!out) return;

  char buffer[PingPacket::PacketSize];
  void* buf = buffer;
  buf = nboPackUShort(buf, PingPacket::PacketSize - 4);
  buf = nboPackUShort(buf, MsgPingCodeReply);
  buf = pack(buf, getServerVersion());
  out.write(buffer,sizeof(buffer));
}

// de serialize packet from file
// must read from a binary file if we use plain "unpack"
bool			 PingPacket::readFromFile(std::istream& in)
{
  if (!in) return false;

  char buffer[PingPacket::PacketSize], serverVersion[9];
  uint16_t len, code;

  // get packet
  in.read(buffer, sizeof(buffer));
  if ((size_t)in.gcount() < sizeof(buffer)){
    return false;
  }

  // decode header
  void* buf = buffer;
  buf = nboUnpackUShort(buf, len);
  buf = nboUnpackUShort(buf, code);

  // make sure we got the rest of the message
  if (len != in.gcount() - 4){
    return false;
  }

  // unpack body of reply
  buf = unpack(buf, serverVersion);

  // compare protocol version against my protocol version.
  return (strcmp(serverVersion, getServerVersion()) == 0);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>Should also revert this, but use full 8 chars to compare for version not just 7<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
// todo make this turn off for .net
#if defined(_MSC_VER)
  #pragma warning(disable: 4786)
#endif

#include <string.h>
#include <math.h>
#include <ctype.h>
#include <fstream>
#include "common.h"
#include "global.h"
#include "Ping.h"
#include "Protocol.h"
#include "TimeKeeper.h"
#include "bzfio.h"

// incessint rebuilding for current versioning
#include "version.h"

//
// PingPacket
//

const int		PingPacket::PacketSize = ServerIdPLen + 52;

PingPacket::PingPacket() : gameStyle(PlainGameStyle),
				maxShots(1),
				shakeWins(0),
				shakeTimeout(0),
				maxPlayerScore(0),
				maxTeamScore(0),
				maxTime(0),
				maxPlayers(1),
				rogueCount(0),
				rogueMax(1),
				redCount(0),
				redMax(1),
				greenCount(0),
				greenMax(1),
				blueCount(0),
				blueMax(1),
				purpleCount(0),
				purpleMax(1),
				observerCount(0),
				observerMax(1)
{
  // do nothing
}

PingPacket::~PingPacket()
{
  // do nothing
}

bool			PingPacket::read(int fd, struct sockaddr_in* addr)
{
  char buffer[PacketSize], serverVersion[9];
  uint16_t len, code;

  // get packet
  int n = recvMulticast(fd, buffer, sizeof(buffer), addr);
  if (n < 4)
    return false;

  // decode header
  void* buf = buffer;
  buf = nboUnpackUShort(buf, len);
  buf = nboUnpackUShort(buf, code);

  // make sure we got the rest of the message
  if (len != n - 4)
    return false;

  // check that it's a reply
  if (code != MsgPingCodeReply)
    return false;

  // unpack body of reply
  buf = unpack(buf, serverVersion);

  // compare protocol version against my protocol version.
  return (strncmp(serverVersion, getServerVersion(), 8) == 0);
}

bool			PingPacket::waitForReply(int fd,
				const Address& from,
				int millisecondsToBlock)
{
  // block waiting on input.  if the incoming message is not from the
  // indicated source then ignore it and go back to waiting.  if the
  // incoming message is not a ping then ignore it and go back to waiting.
  float blockTime = 0.0001f * (float)millisecondsToBlock;
  TimeKeeper startTime = TimeKeeper::getCurrent();
  TimeKeeper currentTime = startTime;
  do {
    // prepare timeout
    const float timeLeft = blockTime - (currentTime - startTime);
    struct timeval timeout;
    timeout.tv_sec = long(floorf(timeLeft));
    timeout.tv_usec = long(1.0e+6f * (timeLeft - floorf(timeLeft)));

    // wait for input
    fd_set read_set;
    FD_ZERO(&read_set);
    _FD_SET(fd, &read_set);
    int nfound = select(fd+1, (fd_set*)&read_set, NULL, NULL, &timeout);

    // if got a message read it.  if a ping packet and from right
    // sender then return success.
    if (nfound < 0)
      return false;
    if (nfound > 0 && read(fd, NULL))
      if (sourceAddr == from)
	return true;

    currentTime = TimeKeeper::getCurrent();
  } while (currentTime - startTime < blockTime);
  return false;
}

bool			PingPacket::write(int fd,
					const struct sockaddr_in* addr) const
{
  char buffer[PacketSize] = {0};
  void* buf = buffer;
  buf = nboPackUShort(buf, PacketSize - 4);
  buf = nboPackUShort(buf, MsgPingCodeReply);
  buf = pack(buf, getServerVersion());
  return sendMulticast(fd, buffer, sizeof(buffer), addr) == sizeof(buffer);
}

bool			PingPacket::isRequest(int fd,
				struct sockaddr_in* addr)
{
  if (fd < 0) return false;
  char buffer[6];
  void *msg = buffer;
  uint16_t len, code;
  int size = recvMulticast(fd, buffer, sizeof(buffer), addr);
  if (size < 2) return false;
  msg = nboUnpackUShort(msg, len);
  msg = nboUnpackUShort(msg, code);
  return code == MsgPingCodeRequest;
}

bool			PingPacket::sendRequest(int fd,
					const struct sockaddr_in* addr)
{
  if (fd < 0 || !addr) return false;
  char buffer[6];
  void *msg = buffer;
  msg = nboPackUShort(msg, 2);
  msg = nboPackUShort(msg, MsgPingCodeRequest);
  msg = nboPackUShort(msg, (uint16_t) 0);
  return sendMulticast(fd, buffer, sizeof(buffer), addr) == sizeof(buffer);
}

void*			PingPacket::unpack(void* buf, char* version)
{
  buf = nboUnpackString(buf, version, 8);
  buf = serverId.unpack(buf);
  buf = sourceAddr.unpack(buf);
  buf = nboUnpackUShort(buf, gameStyle);
  buf = nboUnpackUShort(buf, maxShots);
  buf = nboUnpackUShort(buf, shakeWins);
  buf = nboUnpackUShort(buf, shakeTimeout);
  buf = nboUnpackUShort(buf, maxPlayerScore);
  buf = nboUnpackUShort(buf, maxTeamScore);
  buf = nboUnpackUShort(buf, maxTime);
  buf = nboUnpackUByte(buf, maxPlayers);
  buf = nboUnpackUByte(buf, rogueCount);
  buf = nboUnpackUByte(buf, rogueMax);
  buf = nboUnpackUByte(buf, redCount);
  buf = nboUnpackUByte(buf, redMax);
  buf = nboUnpackUByte(buf, greenCount);
  buf = nboUnpackUByte(buf, greenMax);
  buf = nboUnpackUByte(buf, blueCount);
  buf = nboUnpackUByte(buf, blueMax);
  buf = nboUnpackUByte(buf, purpleCount);
  buf = nboUnpackUByte(buf, purpleMax);
  buf = nboUnpackUByte(buf, observerCount);
  buf = nboUnpackUByte(buf, observerMax);
  return buf;
}

void*			PingPacket::pack(void* buf, const char* version) const
{
  buf = nboPackString(buf, version, 8);
  buf = serverId.pack(buf);
  buf = sourceAddr.pack(buf);
  buf = nboPackUShort(buf, gameStyle);
  buf = nboPackUShort(buf, maxShots);
  buf = nboPackUShort(buf, shakeWins);
  buf = nboPackUShort(buf, shakeTimeout);	// 1/10ths of second
  buf = nboPackUShort(buf, maxPlayerScore);
  buf = nboPackUShort(buf, maxTeamScore);
  buf = nboPackUShort(buf, maxTime);
  buf = nboPackUByte(buf, maxPlayers);
  buf = nboPackUByte(buf, rogueCount);
  buf = nboPackUByte(buf, rogueMax);
  buf = nboPackUByte(buf, redCount);
  buf = nboPackUByte(buf, redMax);
  buf = nboPackUByte(buf, greenCount);
  buf = nboPackUByte(buf, greenMax);
  buf = nboPackUByte(buf, blueCount);
  buf = nboPackUByte(buf, blueMax);
  buf = nboPackUByte(buf, purpleCount);
  buf = nboPackUByte(buf, purpleMax);
  buf = nboPackUByte(buf, observerCount);
  buf = nboPackUByte(buf, observerMax);
  return buf;
}

void			PingPacket::packHex(char* buf) const
{
  buf = packHex16(buf, gameStyle);
  buf = packHex16(buf, maxShots);
  buf = packHex16(buf, shakeWins);
  buf = packHex16(buf, shakeTimeout);
  buf = packHex16(buf, maxPlayerScore);
  buf = packHex16(buf, maxTeamScore);
  buf = packHex16(buf, maxTime);
  buf = packHex8(buf, maxPlayers);
  buf = packHex8(buf, rogueCount);
  buf = packHex8(buf, rogueMax);
  buf = packHex8(buf, redCount);
  buf = packHex8(buf, redMax);
  buf = packHex8(buf, greenCount);
  buf = packHex8(buf, greenMax);
  buf = packHex8(buf, blueCount);
  buf = packHex8(buf, blueMax);
  buf = packHex8(buf, purpleCount);
  buf = packHex8(buf, purpleMax);
  buf = packHex8(buf, observerCount);
  buf = packHex8(buf, observerMax);
  *buf = 0;
}

void			PingPacket::unpackHex(char* buf)
{
  buf = unpackHex16(buf, gameStyle);
  buf = unpackHex16(buf, maxShots);
  buf = unpackHex16(buf, shakeWins);
  buf = unpackHex16(buf, shakeTimeout);
  buf = unpackHex16(buf, maxPlayerScore);
  buf = unpackHex16(buf, maxTeamScore);
  buf = unpackHex16(buf, maxTime);
  buf = unpackHex8(buf, maxPlayers);
  buf = unpackHex8(buf, rogueCount);
  buf = unpackHex8(buf, rogueMax);
  buf = unpackHex8(buf, redCount);
  buf = unpackHex8(buf, redMax);
  buf = unpackHex8(buf, greenCount);
  buf = unpackHex8(buf, greenMax);
  buf = unpackHex8(buf, blueCount);
  buf = unpackHex8(buf, blueMax);
  buf = unpackHex8(buf, purpleCount);
  buf = unpackHex8(buf, purpleMax);
  buf = unpackHex8(buf, observerCount);
  buf = unpackHex8(buf, observerMax);
}

int			PingPacket::hex2bin(char d)
{
  switch (d) {
    case '0': return 0;
    case '1': return 1;
    case '2': return 2;
    case '3': return 3;
    case '4': return 4;
    case '5': return 5;
    case '6': return 6;
    case '7': return 7;
    case '8': return 8;
    case '9': return 9;
    case 'A':
    case 'a': return 10;
    case 'B':
    case 'b': return 11;
    case 'C':
    case 'c': return 12;
    case 'D':
    case 'd': return 13;
    case 'E':
    case 'e': return 14;
    case 'F':
    case 'f': return 15;
  }
  return 0;
}

char			PingPacket::bin2hex(int d)
{
  static const char* digit = "0123456789abcdef";
  return digit[d];
}

char*			PingPacket::packHex16(char* buf, uint16_t v)
{
  *buf++ = bin2hex((v >> 12) & 0xf);
  *buf++ = bin2hex((v >>  8) & 0xf);
  *buf++ = bin2hex((v >>  4) & 0xf);
  *buf++ = bin2hex( v        & 0xf);
  return buf;
}

char*			PingPacket::unpackHex16(char* buf, uint16_t& v)
{
  uint16_t d = 0;
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  v = d;
  return buf;
}

char*			PingPacket::packHex8(char* buf, uint8_t v)
{
  *buf++ = bin2hex((v >>  4) & 0xf);
  *buf++ = bin2hex( v        & 0xf);
  return buf;
}

char*			PingPacket::unpackHex8(char* buf, uint8_t& v)
{
  uint16_t d = 0;
  d = (d << 4) | hex2bin(*buf++);
  d = (d << 4) | hex2bin(*buf++);
  v = (uint8_t)d;
  return buf;
}

void			 PingPacket::zeroPlayerCounts()
{
  rogueCount = 0;
  redCount = 0;
  greenCount = 0;
  blueCount = 0;
  purpleCount = 0;
  observerCount = 0;
}

// serialize packet to file -- note lack of error checking
// must write to a binary file if we use plain "pack"
void			 PingPacket::writeToFile (std::ostream& out) const
{
  if (!out) return;

  char buffer[PingPacket::PacketSize];
  void* buf = buffer;
  buf = nboPackUShort(buf, PingPacket::PacketSize - 4);
  buf = nboPackUShort(buf, MsgPingCodeReply);
  buf = pack(buf, getServerVersion());
  out.write(buffer,sizeof(buffer));
}

// de serialize packet from file
// must read from a binary file if we use plain "unpack"
bool			 PingPacket::readFromFile(std::istream& in)
{
  if (!in) return false;

  char buffer[PingPacket::PacketSize], serverVersion[9];
  uint16_t len, code;

  // get packet
  in.read(buffer, sizeof(buffer));
  if ((size_t)in.gcount() < sizeof(buffer)){
    return false;
  }

  // decode header
  void* buf = buffer;
  buf = nboUnpackUShort(buf, len);
  buf = nboUnpackUShort(buf, code);

  // make sure we got the rest of the message
  if (len != in.gcount() - 4){
    return false;
  }

  // unpack body of reply
  buf = unpack(buf, serverVersion);

  // compare protocol version against my protocol version.
  return (strncmp(serverVersion, getServerVersion(), 8) == 0);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>