/*
 * Copyright 2021 Bloomberg Finance LP
 *
 * 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 <buildboxcommon_executionstatsutils.h>

#include <buildboxcommon_logging.h>
#include <buildboxcommon_timeutils.h>

#include <google/protobuf/util/time_util.h>

#include <cstring>

namespace buildboxcommon {

build::buildbox::ExecutionStatistics
ExecutionStatsUtils::getChildrenProcessRusage()
{
    build::buildbox::ExecutionStatistics stats;

    struct rusage r{};
    const auto status = getrusage(RUSAGE_CHILDREN, &r);
    if (status == 0) {
        *stats.mutable_command_rusage() = processResourceUsageFromRusage(r);
    }
    else {
        const auto error = errno;
        BUILDBOX_LOG_WARNING("rusage() failed: " << error << ": "
                                                 << strerror(errno));
    }

    return stats;
}

build::buildbox::ExecutionStatistics_ProcessResourceUsage
ExecutionStatsUtils::processResourceUsageFromRusage(const rusage &ru)
{
    build::buildbox::ExecutionStatistics_ProcessResourceUsage proto;

    // System time:
    *proto.mutable_stime() =
        google::protobuf::util::TimeUtil::TimevalToDuration(ru.ru_stime);

    // User time:
    *proto.mutable_utime() =
        google::protobuf::util::TimeUtil::TimevalToDuration(ru.ru_utime);

    // NOLINTBEGIN (cppcoreguidelines-pro-type-union-access)
    // Max. resident size:
    proto.set_maxrss(ru.ru_maxrss);

    // Page faults/reclaims:
    proto.set_majflt(ru.ru_majflt);
    proto.set_minflt(ru.ru_minflt);

    // I/O
    proto.set_inblock(ru.ru_inblock);
    proto.set_oublock(ru.ru_oublock);

    // Context switches:
    proto.set_nvcsw(ru.ru_nvcsw);
    proto.set_nivcsw(ru.ru_nivcsw);
    // NOLINTEND (cppcoreguidelines-pro-type-union-access)

    return proto;
}

} // namespace buildboxcommon
