GMLC-TDC / HELICS

@@ -57,6 +57,7 @@
Loading
57 57
            return estate;
58 58
    }
59 59
}
60 +
60 61
// timeoutMon is a unique_ptr
61 62
CommonCore::CommonCore() noexcept: timeoutMon(new TimeoutMonitor) {}
62 63
@@ -1950,12 +1951,14 @@
Loading
1950 1951
    current_time_map = 2,
1951 1952
    dependency_graph = 3,
1952 1953
    data_flow_graph = 4,
1954 +
    global_state = 6,
1953 1955
};
1954 1956
1955 1957
static const std::map<std::string, std::pair<std::uint16_t, bool>> mapIndex{
1956 1958
    {"global_time", {current_time_map, true}},
1957 1959
    {"dependency_graph", {dependency_graph, false}},
1958 1960
    {"data_flow_graph", {data_flow_graph, false}},
1961 +
    {"global_state", {global_state, true}},
1959 1962
};
1960 1963
1961 1964
void CommonCore::setQueryCallback(local_federate_id federateID,
@@ -2055,14 +2058,14 @@
Loading
2055 2058
        return (fed->init_transmitted.load()) ? "true" : "false";
2056 2059
    }
2057 2060
    if (queryStr == "state") {
2058 -
        return std::to_string(static_cast<int>(fed->getState()));
2061 +
        return fedStateString(fed->getState());
2059 2062
    }
2060 2063
    if (queryStr == "filtered_endpoints") {
2061 2064
        return filteredEndpointQuery(fed);
2062 2065
    }
2063 2066
    if ((queryStr == "queries") || (queryStr == "available_queries")) {
2064 2067
        return std::string(
2065 -
                   "[exists;isinit;state;version;queries;filtered_endpoints;current_time;") +
2068 +
                   "[exists;isinit;state;global_state;version;queries;filtered_endpoints;current_time;") +
2066 2069
            fed->processQuery(queryStr) + "]";
2067 2070
    }
2068 2071
    return fed->processQuery(queryStr);
@@ -2072,7 +2075,7 @@
Loading
2072 2075
{
2073 2076
    if ((queryStr == "queries") || (queryStr == "available_queries")) {
2074 2077
        return "[isinit;isconnected;exists;name;identifier;address;queries;address;federates;inputs;endpoints;filtered_endpoints;"
2075 -
               "publications;filters;version;version_all;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;current_time;global_time;current_state]";
2078 +
               "publications;filters;version;version_all;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;current_time;global_time;global_state;current_state]";
2076 2079
    }
2077 2080
    if (queryStr == "isconnected") {
2078 2081
        return (isConnected()) ? "true" : "false";
@@ -2131,7 +2134,8 @@
Loading
2131 2134
    if (loopFederates.size() > 0) {
2132 2135
        base["federates"] = Json::arrayValue;
2133 2136
        for (const auto& fed : loopFederates) {
2134 -
            int brkindex = builder.generatePlaceHolder("federates");
2137 +
            int brkindex =
2138 +
                builder.generatePlaceHolder("federates", fed->global_id.load().baseValue());
2135 2139
            std::string ret = federateQuery(fed.fed, request);
2136 2140
            if (ret == "#wait") {
2137 2141
                queryReq.messageID = brkindex;
@@ -2182,6 +2186,9 @@
Loading
2182 2186
                }
2183 2187
            }
2184 2188
            break;
2189 +
        case global_state:
2190 +
            base["state"] = brokerStateName(brokerState.load());
2191 +
            break;
2185 2192
        default:
2186 2193
            break;
2187 2194
    }

@@ -314,6 +314,8 @@
Loading
314 314
    void disconnectBroker(BasicBrokerInfo& brk);
315 315
    /** mark this broker and all other that have this as a parent as disconnected*/
316 316
    void markAsDisconnected(global_broker_id brkid);
317 +
    /** check to make sure there are no inflight queries that need to be resolved*/
318 +
    void checkInFlightQueries(global_broker_id brkid);
317 319
    /** run a check for a named interface*/
318 320
    void checkForNamedInterface(ActionMessage& command);
319 321
    /** remove a named target from an interface*/

@@ -163,7 +163,7 @@
Loading
163 163
}
164 164
federate_state FederateState::getState() const
165 165
{
166 -
    return state;
166 +
    return state.load();
167 167
}
168 168
169 169
int32_t FederateState::getCurrentIteration() const
@@ -1650,6 +1650,35 @@
Loading
1650 1650
    }
1651 1651
}
1652 1652
1653 +
const std::string& fedStateString(federate_state state)
1654 +
{
1655 +
    static const std::string c1{"created"};
1656 +
    static const std::string estate{"error"};
1657 +
    static const std::string init{"initializing"};
1658 +
    static const std::string dis{"disconnected"};
1659 +
    static const std::string exec{"executing"};
1660 +
    static const std::string term{"terminating"};
1661 +
    static const std::string unk{"unknown"};
1662 +
1663 +
    switch (state) {
1664 +
        case federate_state::HELICS_CREATED:
1665 +
            return c1;
1666 +
        case federate_state::HELICS_INITIALIZING:
1667 +
            return init;
1668 +
        case federate_state::HELICS_EXECUTING:
1669 +
            return exec;
1670 +
        case federate_state::HELICS_TERMINATING:
1671 +
            return term;
1672 +
        case federate_state::HELICS_FINISHED:
1673 +
            return dis;
1674 +
        case federate_state::HELICS_ERROR:
1675 +
            return estate;
1676 +
        case federate_state::HELICS_UNKNOWN:
1677 +
        default:
1678 +
            return unk;
1679 +
    }
1680 +
}
1681 +
1653 1682
std::string FederateState::processQueryActual(const std::string& query) const
1654 1683
{
1655 1684
    if (query == "publications") {
@@ -1699,13 +1728,21 @@
Loading
1699 1728
        base["name"] = getIdentifier();
1700 1729
        base["id"] = global_id.load().baseValue();
1701 1730
        base["parent"] = parent_->getGlobalId().baseValue();
1702 -
        base["state"] = static_cast<int>(state.load());
1731 +
        base["state"] = fedStateString(state.load());
1703 1732
        base["publications"] = publicationCount();
1704 1733
        base["input"] = inputCount();
1705 1734
        base["endpoints"] = endpointCount();
1706 1735
        base["granted_time"] = static_cast<double>(grantedTime());
1707 1736
        return generateJsonString(base);
1708 1737
    }
1738 +
    if (query == "global_state") {
1739 +
        Json::Value base;
1740 +
        base["name"] = getIdentifier();
1741 +
        base["id"] = global_id.load().baseValue();
1742 +
        base["parent"] = parent_->getGlobalId().baseValue();
1743 +
        base["state"] = fedStateString(state.load());
1744 +
        return generateJsonString(base);
1745 +
    }
1709 1746
    if (query == "timeconfig") {
1710 1747
        Json::Value base;
1711 1748
        timeCoord->generateConfig(base);
@@ -1764,12 +1801,12 @@
Loading
1764 1801
std::string FederateState::processQuery(const std::string& query) const
1765 1802
{
1766 1803
    std::string qstring;
1767 -
    if (query == "publications" || query == "inputs" ||
1768 -
        query == "endpoints") {  // these never need to be locked
1804 +
    if (query == "publications" || query == "inputs" || query == "endpoints" ||
1805 +
        query == "global_state") {  // these never need to be locked
1769 1806
        qstring = processQueryActual(query);
1770 1807
    } else if ((query == "queries") || (query == "available_queries")) {
1771 1808
        qstring =
1772 -
            "publications;inputs;endpoints;interfaces;subscriptions;dependencies;timeconfig;config;dependents;current_time";
1809 +
            "publications;inputs;endpoints;interfaces;subscriptions;current_state;global_state;dependencies;timeconfig;config;dependents;current_time";
1773 1810
    } else {  // the rest might to prevent a race condition
1774 1811
        if (try_lock()) {
1775 1812
            qstring = processQueryActual(query);

@@ -2296,6 +2296,40 @@
Loading
2296 2296
    }
2297 2297
}
2298 2298
2299 +
void CoreBroker::checkInFlightQueries(global_broker_id brkid)
2300 +
{
2301 +
    for (auto& mb : mapBuilders) {
2302 +
        auto& builder = std::get<0>(mb);
2303 +
        auto& requestors = std::get<1>(mb);
2304 +
        if (builder.isCompleted()) {
2305 +
            return;
2306 +
        }
2307 +
        if (builder.clearComponents(brkid.baseValue())) {
2308 +
            auto str = builder.generate();
2309 +
            for (int ii = 0; ii < static_cast<int>(requestors.size()) - 1; ++ii) {
2310 +
                if (requestors[ii].dest_id == global_broker_id_local) {
2311 +
                    activeQueries.setDelayedValue(requestors[ii].messageID, str);
2312 +
                } else {
2313 +
                    requestors[ii].payload = str;
2314 +
                    routeMessage(std::move(requestors[ii]));
2315 +
                }
2316 +
            }
2317 +
            if (requestors.back().dest_id == global_broker_id_local) {
2318 +
                // TODO(PT) add rvalue reference method
2319 +
                activeQueries.setDelayedValue(requestors.back().messageID, str);
2320 +
            } else {
2321 +
                requestors.back().payload = std::move(str);
2322 +
                routeMessage(std::move(requestors.back()));
2323 +
            }
2324 +
2325 +
            requestors.clear();
2326 +
            if (std::get<2>(mb)) {
2327 +
                builder.reset();
2328 +
            }
2329 +
        }
2330 +
    }
2331 +
}
2332 +
2299 2333
void CoreBroker::markAsDisconnected(global_broker_id brkid)
2300 2334
{
2301 2335
    bool isCore{false};
@@ -2331,6 +2365,7 @@
Loading
2331 2365
void CoreBroker::disconnectBroker(BasicBrokerInfo& brk)
2332 2366
{
2333 2367
    markAsDisconnected(brk.global_id);
2368 +
    checkInFlightQueries(brk.global_id);
2334 2369
    if (brokerState < broker_state_t::operating) {
2335 2370
        if (isRootc) {
2336 2371
            ActionMessage dis(CMD_BROADCAST_DISCONNECT);
@@ -2437,7 +2472,8 @@
Loading
2437 2472
    current_time_map = 2,
2438 2473
    dependency_graph = 3,
2439 2474
    data_flow_graph = 4,
2440 -
    version_all = 5
2475 +
    version_all = 5,
2476 +
    global_state = 6
2441 2477
};
2442 2478
2443 2479
static const std::map<std::string, std::pair<std::uint16_t, bool>> mapIndex{
@@ -2446,6 +2482,7 @@
Loading
2446 2482
    {"dependency_graph", {dependency_graph, false}},
2447 2483
    {"data_flow_graph", {data_flow_graph, false}},
2448 2484
    {"version_all", {version_all, false}},
2485 +
    {"global_state", {global_state, true}},
2449 2486
};
2450 2487
2451 2488
std::string CoreBroker::generateQueryAnswer(const std::string& request)
@@ -2466,7 +2503,7 @@
Loading
2466 2503
    if ((request == "queries") || (request == "available_queries")) {
2467 2504
        return "[isinit;isconnected;name;identifier;address;queries;address;counts;summary;federates;brokers;inputs;endpoints;"
2468 2505
               "publications;filters;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;"
2469 -
               "current_time;current_state;status;global_time;version;version_all;exists]";
2506 +
               "current_time;current_state;global_state;status;global_time;version;version_all;exists]";
2470 2507
    }
2471 2508
    if (request == "address") {
2472 2509
        return getAddress();
@@ -2528,8 +2565,8 @@
Loading
2528 2565
            fedstate["id"] = fed.global_id.baseValue();
2529 2566
            base["federates"].append(std::move(fedstate));
2530 2567
        }
2531 -
        base["brokers"] = Json::arrayValue;
2532 2568
        base["cores"] = Json::arrayValue;
2569 +
        base["brokers"] = Json::arrayValue;
2533 2570
        for (const auto& brk : _brokers) {
2534 2571
            Json::Value brkstate;
2535 2572
            brkstate["state"] = state_string(brk.state);
@@ -2677,21 +2714,57 @@
Loading
2677 2714
    queryReq.source_id = global_broker_id_local;
2678 2715
    queryReq.counter = index;  // indicating which processing to use
2679 2716
    bool hasCores = false;
2717 +
    bool hasBrokers = false;
2680 2718
    for (const auto& broker : _brokers) {
2681 2719
        if (broker.parent == global_broker_id_local) {
2682 -
            int brkindex;
2683 -
            if (broker._core) {
2684 -
                if (!hasCores) {
2685 -
                    hasCores = true;
2686 -
                    base["cores"] = Json::arrayValue;
2687 -
                }
2688 -
                brkindex = builder.generatePlaceHolder("cores");
2689 -
            } else {
2690 -
                brkindex = builder.generatePlaceHolder("brokers");
2720 +
            switch (broker.state) {
2721 +
                case connection_state::connected:
2722 +
                case connection_state::init_requested:
2723 +
                case connection_state::operating: {
2724 +
                    int brkindex;
2725 +
                    if (broker._core) {
2726 +
                        if (!hasCores) {
2727 +
                            hasCores = true;
2728 +
                            base["cores"] = Json::arrayValue;
2729 +
                        }
2730 +
                        brkindex =
2731 +
                            builder.generatePlaceHolder("cores", broker.global_id.baseValue());
2732 +
                    } else {
2733 +
                        if (!hasBrokers) {
2734 +
                            hasBrokers = true;
2735 +
                            base["brokers"] = Json::arrayValue;
2736 +
                        }
2737 +
                        brkindex =
2738 +
                            builder.generatePlaceHolder("brokers", broker.global_id.baseValue());
2739 +
                    }
2740 +
                    queryReq.messageID = brkindex;
2741 +
                    queryReq.dest_id = broker.global_id;
2742 +
                    transmit(broker.route, queryReq);
2743 +
                } break;
2744 +
                case connection_state::error:
2745 +
                case connection_state::disconnected:
2746 +
                case connection_state::request_disconnect:
2747 +
                    if (index == global_state) {
2748 +
                        Json::Value brkstate;
2749 +
                        brkstate["state"] = state_string(broker.state);
2750 +
                        brkstate["name"] = broker.name;
2751 +
                        brkstate["id"] = broker.global_id.baseValue();
2752 +
                        if (broker._core) {
2753 +
                            if (!hasCores) {
2754 +
                                base["cores"] = Json::arrayValue;
2755 +
                                hasCores = true;
2756 +
                            }
2757 +
                            base["cores"].append(std::move(brkstate));
2758 +
                        } else {
2759 +
                            if (!hasBrokers) {
2760 +
                                base["brokers"] = Json::arrayValue;
2761 +
                                hasBrokers = true;
2762 +
                            }
2763 +
                            base["brokers"].append(std::move(brkstate));
2764 +
                        }
2765 +
                    }
2766 +
                    break;
2691 2767
            }
2692 -
            queryReq.messageID = brkindex;
2693 -
            queryReq.dest_id = broker.global_id;
2694 -
            transmit(broker.route, queryReq);
2695 2768
        }
2696 2769
    }
2697 2770
    switch (index) {
@@ -2713,6 +2786,10 @@
Loading
2713 2786
        case version_all:
2714 2787
            base["version"] = versionString;
2715 2788
            break;
2789 +
        case global_state:
2790 +
            base["state"] = brokerStateName(brokerState.load());
2791 +
            base["status"] = isConnected();
2792 +
            break;
2716 2793
    }
2717 2794
}
2718 2795

@@ -391,4 +391,7 @@
Loading
391 391
    /** close an interface*/
392 392
    void closeInterface(interface_handle handle, handle_type type);
393 393
};
394 +
395 +
/** convert the state into a human readable string*/
396 +
const std::string& fedStateString(federate_state state);
394 397
}  // namespace helics

@@ -32,10 +32,10 @@
Loading
32 32
    return (jMap) && (missing_components.empty());
33 33
}
34 34
35 -
int JsonMapBuilder::generatePlaceHolder(const std::string& location)
35 +
int JsonMapBuilder::generatePlaceHolder(const std::string& location, int32_t code)
36 36
{
37 37
    int index = static_cast<int>(missing_components.size()) + 2;
38 -
    missing_components.emplace(index, location);
38 +
    missing_components.emplace(index, std::make_pair(location, code));
39 39
    return index;
40 40
}
41 41
@@ -44,14 +44,14 @@
Loading
44 44
    auto loc = missing_components.find(index);
45 45
    if (loc != missing_components.end()) {
46 46
        if (info == "#invalid") {
47 -
            (*jMap)[loc->second].append(Json::Value{});
47 +
            (*jMap)[loc->second.first].append(Json::Value{});
48 48
        } else {
49 49
            try {
50 50
                auto element = loadJsonStr(info);
51 -
                (*jMap)[loc->second].append(element);
51 +
                (*jMap)[loc->second.first].append(element);
52 52
            }
53 53
            catch (const std::invalid_argument&) {
54 -
                (*jMap)[loc->second].append(Json::Value{});
54 +
                (*jMap)[loc->second.first].append(Json::Value{});
55 55
            }
56 56
        }
57 57
@@ -62,6 +62,17 @@
Loading
62 62
    return false;
63 63
}
64 64
65 +
bool JsonMapBuilder::clearComponents(int32_t code)
66 +
{
67 +
    for (auto b = missing_components.begin(); b != missing_components.end(); ++b) {
68 +
        if (b->second.second == code) {
69 +
            missing_components.erase(b);
70 +
            return missing_components.empty();
71 +
        }
72 +
    }
73 +
    return false;
74 +
}
75 +
65 76
std::string JsonMapBuilder::generate()
66 77
{
67 78
    if (jMap) {
@@ -84,7 +95,7 @@
Loading
84 95
{
85 96
    stringVector res = gmlc::utilities::stringOps::splitline(
86 97
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
87 -
    auto jv = &getJValue();
98 +
    auto* jv = &getJValue();
88 99
    size_t ii = 0;
89 100
    for (ii = 0; ii < res.size() - 1; ++ii) {
90 101
        auto& sub = (*jv)[res[ii]];
@@ -100,7 +111,7 @@
Loading
100 111
{
101 112
    stringVector res = gmlc::utilities::stringOps::splitline(
102 113
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
103 -
    auto jv = &getJValue();
114 +
    auto* jv = &getJValue();
104 115
    size_t ii = 0;
105 116
    for (ii = 0; ii < res.size() - 1; ++ii) {
106 117
        auto& sub = (*jv)[res[ii]];
@@ -116,7 +127,7 @@
Loading
116 127
{
117 128
    stringVector res = gmlc::utilities::stringOps::splitline(
118 129
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
119 -
    auto jv = &getJValue();
130 +
    auto* jv = &getJValue();
120 131
    size_t ii = 0;
121 132
    for (ii = 0; ii < res.size() - 1; ++ii) {
122 133
        auto& sub = (*jv)[res[ii]];
@@ -126,7 +137,7 @@
Loading
126 137
        jv = &(*jv)[res[ii]];
127 138
    }
128 139
    (*jv)[res.back()] = Json::arrayValue;
129 -
    for (auto& v : value) {
140 +
    for (const auto& v : value) {
130 141
        (*jv)[res.back()].append(v);
131 142
    }
132 143
}

@@ -8,6 +8,7 @@
Loading
8 8
#include <map>
9 9
#include <memory>
10 10
#include <string>
11 +
#include <utility>
11 12
#include <vector>
12 13
13 14
namespace Json {
@@ -19,7 +20,7 @@
Loading
19 20
class JsonMapBuilder {
20 21
  private:
21 22
    std::unique_ptr<Json::Value> jMap;
22 -
    std::map<int, std::string> missing_components;
23 +
    std::map<int, std::pair<std::string, int32_t>> missing_components;
23 24
24 25
  public:
25 26
    JsonMapBuilder() noexcept;
@@ -40,8 +41,9 @@
Loading
40 41
    bool addComponent(const std::string& info, int index) noexcept;
41 42
    /** generate a new location to fill in later
42 43
    @return the index value of the location for use in addComponent*/
43 -
    int generatePlaceHolder(const std::string& location);
44 +
    int generatePlaceHolder(const std::string& location, int32_t code);
44 45
    /** generate the JSON value*/
46 +
    bool clearComponents(int32_t code);
45 47
    std::string generate();
46 48
    /** reset the builder*/
47 49
    void reset();
Files Coverage
src/helics 76.88%
Project Totals (210 files) 76.88%
12725.9
TRAVIS_OS_NAME=linux
1
codecov:
2
  notify:
3
    require_ci_to_pass: no
4
  branch: develop
5

6
coverage:
7
  precision: 2
8
  round: down
9
  range: '50...95'
10
  status:
11
    project: yes
12
    patch: yes
13
    changes: no
14

15
parsers:
16
  gcov:
17
    branch_detection:
18
      conditional: yes
19
      loop: yes
20
      method: no
21
      macro: no
22

23
comment:
24
  layout: 'header, diff'
25
  behavior: default
26
  require_changes: no
27

28
ignore:
29
  - 'ThirdParty'
30
  - 'examples'
31
  - 'tests'
32
  - 'interfaces'
33
  - 'src/helics/core/mpi'
34
  - '**/logger.*'
35
  - '**/loggerCore.*'
36
  - '**/zmqHelper.*'
37
  - 'src/helics/shared_api_library/internal/api_objects.h'
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading