12SN/A/*
210905Sandreas.sandberg@arm.com * Copyright (c) 2015 ARM Limited
310905Sandreas.sandberg@arm.com * All rights reserved
410905Sandreas.sandberg@arm.com *
510905Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
610905Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
710905Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
810905Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
910905Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1010905Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1110905Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1210905Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1310905Sandreas.sandberg@arm.com *
141762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
159983Sstever@gmail.com * Copyright (c) 2013 Advanced Micro Devices, Inc.
169983Sstever@gmail.com * Copyright (c) 2013 Mark D. Hill and David A. Wood
172SN/A * All rights reserved.
182SN/A *
192SN/A * Redistribution and use in source and binary forms, with or without
202SN/A * modification, are permitted provided that the following conditions are
212SN/A * met: redistributions of source code must retain the above copyright
222SN/A * notice, this list of conditions and the following disclaimer;
232SN/A * redistributions in binary form must reproduce the above copyright
242SN/A * notice, this list of conditions and the following disclaimer in the
252SN/A * documentation and/or other materials provided with the distribution;
262SN/A * neither the name of the copyright holders nor the names of its
272SN/A * contributors may be used to endorse or promote products derived from
282SN/A * this software without specific prior written permission.
292SN/A *
302SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
312SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
322SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
332SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
342SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
352SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
362SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
372SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
382SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
392SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
402SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
412665Ssaidi@eecs.umich.edu *
422760Sbinkertn@umich.edu * Authors: Nathan Binkert
432760Sbinkertn@umich.edu *          Erik Hallnor
442665Ssaidi@eecs.umich.edu *          Steve Reinhardt
4510905Sandreas.sandberg@arm.com *          Andreas Sandberg
462SN/A */
472SN/A
4811793Sbrandon.potter@amd.com#include "sim/serialize.hh"
4911793Sbrandon.potter@amd.com
508229Snate@binkert.org#include <sys/stat.h>
512SN/A#include <sys/time.h>
52363SN/A#include <sys/types.h>
532SN/A
548229Snate@binkert.org#include <cerrno>
552SN/A#include <fstream>
562SN/A#include <list>
572SN/A#include <string>
582SN/A#include <vector>
592SN/A
60363SN/A#include "base/inifile.hh"
611388SN/A#include "base/output.hh"
62363SN/A#include "base/trace.hh"
6310905Sandreas.sandberg@arm.com#include "debug/Checkpoint.hh"
6456SN/A#include "sim/eventq.hh"
6556SN/A#include "sim/sim_events.hh"
661638SN/A#include "sim/sim_exit.hh"
6756SN/A#include "sim/sim_object.hh"
682SN/A
692356SN/A// For stat reset hack
702356SN/A#include "sim/stat_control.hh"
712356SN/A
722SN/Ausing namespace std;
732SN/A
742287SN/Aint Serializable::ckptMaxCount = 0;
752287SN/Aint Serializable::ckptCount = 0;
762287SN/Aint Serializable::ckptPrevCount = -1;
7710905Sandreas.sandberg@arm.comstd::stack<std::string> Serializable::path;
782SN/A
79395SN/A/////////////////////////////
80395SN/A
81395SN/A/// Container for serializing global variables (not associated with
82395SN/A/// any serialized object).
83395SN/Aclass Globals : public Serializable
842SN/A{
85395SN/A  public:
8610905Sandreas.sandberg@arm.com    Globals()
8710905Sandreas.sandberg@arm.com        : unserializedCurTick(0) {}
8810905Sandreas.sandberg@arm.com
8911168Sandreas.hansson@arm.com    void serialize(CheckpointOut &cp) const override;
9011168Sandreas.hansson@arm.com    void unserialize(CheckpointIn &cp) override;
9110905Sandreas.sandberg@arm.com
9210905Sandreas.sandberg@arm.com    Tick unserializedCurTick;
93395SN/A};
942SN/A
95395SN/A/// The one and only instance of the Globals class.
96395SN/AGlobals globals;
972SN/A
9811077SCurtis.Dunham@arm.com/// The version tags for this build of the simulator, to be stored in the
9911077SCurtis.Dunham@arm.com/// Globals section during serialization and compared upon unserialization.
10011077SCurtis.Dunham@arm.comextern std::set<std::string> version_tags;
10111077SCurtis.Dunham@arm.com
10210905Sandreas.sandberg@arm.comvoid
10310905Sandreas.sandberg@arm.comGlobals::serialize(CheckpointOut &cp) const
1042SN/A{
10510905Sandreas.sandberg@arm.com    paramOut(cp, "curTick", curTick());
10611077SCurtis.Dunham@arm.com    SERIALIZE_CONTAINER(version_tags);
1072SN/A}
1082SN/A
1092SN/Avoid
11010905Sandreas.sandberg@arm.comGlobals::unserialize(CheckpointIn &cp)
1112SN/A{
11210905Sandreas.sandberg@arm.com    paramIn(cp, "curTick", unserializedCurTick);
11311077SCurtis.Dunham@arm.com
11411077SCurtis.Dunham@arm.com    const std::string &section(Serializable::currentSection());
11511077SCurtis.Dunham@arm.com    std::string str;
11611077SCurtis.Dunham@arm.com    if (!cp.find(section, "version_tags", str)) {
11711077SCurtis.Dunham@arm.com        warn("**********************************************************\n");
11811077SCurtis.Dunham@arm.com        warn("!!!! Checkpoint uses an old versioning scheme.        !!!!\n");
11911077SCurtis.Dunham@arm.com        warn("Run the checkpoint upgrader (util/cpt_upgrader.py) on your "
12011077SCurtis.Dunham@arm.com             "checkpoint\n");
12111077SCurtis.Dunham@arm.com        warn("**********************************************************\n");
12211077SCurtis.Dunham@arm.com        return;
12311077SCurtis.Dunham@arm.com    }
12411077SCurtis.Dunham@arm.com
12511077SCurtis.Dunham@arm.com    std::set<std::string> cpt_tags;
12611077SCurtis.Dunham@arm.com    arrayParamIn(cp, "version_tags", cpt_tags); // UNSERIALIZE_CONTAINER
12711077SCurtis.Dunham@arm.com
12811077SCurtis.Dunham@arm.com    bool err = false;
12911077SCurtis.Dunham@arm.com    for (const auto& t : version_tags) {
13011077SCurtis.Dunham@arm.com        if (cpt_tags.find(t) == cpt_tags.end()) {
13111077SCurtis.Dunham@arm.com            // checkpoint is missing tag that this binary has
13211077SCurtis.Dunham@arm.com            if (!err) {
13311077SCurtis.Dunham@arm.com                warn("*****************************************************\n");
13411077SCurtis.Dunham@arm.com                warn("!!!! Checkpoint is missing the following version tags:\n");
13511077SCurtis.Dunham@arm.com                err = true;
13611077SCurtis.Dunham@arm.com            }
13711077SCurtis.Dunham@arm.com            warn("  %s\n", t);
13811077SCurtis.Dunham@arm.com        }
13911077SCurtis.Dunham@arm.com    }
14011077SCurtis.Dunham@arm.com    if (err) {
14111077SCurtis.Dunham@arm.com        warn("You might experience some issues when restoring and should run "
14211077SCurtis.Dunham@arm.com             "the checkpoint upgrader (util/cpt_upgrader.py) on your "
14311077SCurtis.Dunham@arm.com             "checkpoint\n");
14411077SCurtis.Dunham@arm.com        warn("**********************************************************\n");
14511077SCurtis.Dunham@arm.com    }
14611077SCurtis.Dunham@arm.com
14711077SCurtis.Dunham@arm.com    err = false;
14811077SCurtis.Dunham@arm.com    for (const auto& t : cpt_tags) {
14911077SCurtis.Dunham@arm.com        if (version_tags.find(t) == version_tags.end()) {
15011077SCurtis.Dunham@arm.com            // gem5 binary is missing tag that this checkpoint has
15111077SCurtis.Dunham@arm.com            if (!err) {
15211077SCurtis.Dunham@arm.com                warn("*****************************************************\n");
15311077SCurtis.Dunham@arm.com                warn("!!!! gem5 is missing the following version tags:\n");
15411077SCurtis.Dunham@arm.com                err = true;
15511077SCurtis.Dunham@arm.com            }
15611077SCurtis.Dunham@arm.com            warn("  %s\n", t);
15711077SCurtis.Dunham@arm.com        }
15811077SCurtis.Dunham@arm.com    }
15911077SCurtis.Dunham@arm.com    if (err) {
16011077SCurtis.Dunham@arm.com        warn("Running a checkpoint with incompatible version tags is not "
16111077SCurtis.Dunham@arm.com             "supported. While it might work, you may experience incorrect "
16211077SCurtis.Dunham@arm.com             "behavior or crashes.\n");
16311077SCurtis.Dunham@arm.com        warn("**********************************************************\n");
16411077SCurtis.Dunham@arm.com     }
1652SN/A}
1662SN/A
1675739Snate@binkert.orgSerializable::Serializable()
1685739Snate@binkert.org{
1695739Snate@binkert.org}
1705739Snate@binkert.org
1715739Snate@binkert.orgSerializable::~Serializable()
1725739Snate@binkert.org{
1735739Snate@binkert.org}
1745739Snate@binkert.org
1755739Snate@binkert.orgvoid
17610905Sandreas.sandberg@arm.comSerializable::serializeSection(CheckpointOut &cp, const char *name) const
1775739Snate@binkert.org{
17810905Sandreas.sandberg@arm.com    Serializable::ScopedCheckpointSection sec(cp, name);
17910905Sandreas.sandberg@arm.com    serialize(cp);
1805739Snate@binkert.org}
1815739Snate@binkert.org
1825739Snate@binkert.orgvoid
18310905Sandreas.sandberg@arm.comSerializable::unserializeSection(CheckpointIn &cp, const char *name)
18410905Sandreas.sandberg@arm.com{
18510905Sandreas.sandberg@arm.com    Serializable::ScopedCheckpointSection sec(cp, name);
18610905Sandreas.sandberg@arm.com    unserialize(cp);
1875739Snate@binkert.org}
1885739Snate@binkert.org
1892SN/Avoid
1906225Snate@binkert.orgSerializable::serializeAll(const string &cpt_dir)
1912SN/A{
19210905Sandreas.sandberg@arm.com    string dir = CheckpointIn::setDir(cpt_dir);
193363SN/A    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
194449SN/A            fatal("couldn't mkdir %s\n", dir);
195363SN/A
19610905Sandreas.sandberg@arm.com    string cpt_file = dir + CheckpointIn::baseFilename;
197395SN/A    ofstream outstream(cpt_file.c_str());
1982SN/A    time_t t = time(NULL);
1995581Ssaidi@eecs.umich.edu    if (!outstream.is_open())
2005581Ssaidi@eecs.umich.edu        fatal("Unable to open file %s for writing\n", cpt_file.c_str());
2016818SLisa.Hsu@amd.com    outstream << "## checkpoint generated: " << ctime(&t);
2022SN/A
20310905Sandreas.sandberg@arm.com    globals.serializeSection(outstream, "Globals");
20410905Sandreas.sandberg@arm.com
205395SN/A    SimObject::serializeAll(outstream);
206395SN/A}
2072SN/A
2082797Sktlim@umich.eduvoid
20910905Sandreas.sandberg@arm.comSerializable::unserializeGlobals(CheckpointIn &cp)
210395SN/A{
21110905Sandreas.sandberg@arm.com    globals.unserializeSection(cp, "Globals");
21210905Sandreas.sandberg@arm.com
21311072Sandreas.sandberg@arm.com    for (uint32_t i = 0; i < numMainEventQueues; ++i)
21410905Sandreas.sandberg@arm.com        mainEventQueue[i]->setCurTick(globals.unserializedCurTick);
21510905Sandreas.sandberg@arm.com}
21610905Sandreas.sandberg@arm.com
21710905Sandreas.sandberg@arm.comSerializable::ScopedCheckpointSection::~ScopedCheckpointSection()
21810905Sandreas.sandberg@arm.com{
21910905Sandreas.sandberg@arm.com    assert(!path.empty());
22010905Sandreas.sandberg@arm.com    DPRINTF(Checkpoint, "Popping: %s\n", path.top());
22110905Sandreas.sandberg@arm.com    path.pop();
22210905Sandreas.sandberg@arm.com}
22310905Sandreas.sandberg@arm.com
22410905Sandreas.sandberg@arm.comvoid
22510905Sandreas.sandberg@arm.comSerializable::ScopedCheckpointSection::pushName(const char *obj_name)
22610905Sandreas.sandberg@arm.com{
22710905Sandreas.sandberg@arm.com    if (path.empty()) {
22810905Sandreas.sandberg@arm.com        path.push(obj_name);
22910905Sandreas.sandberg@arm.com    } else {
23010905Sandreas.sandberg@arm.com        path.push(csprintf("%s.%s", path.top(), obj_name));
23110905Sandreas.sandberg@arm.com    }
23210905Sandreas.sandberg@arm.com    DPRINTF(Checkpoint, "ScopedCheckpointSection::pushName: %s\n", obj_name);
23310905Sandreas.sandberg@arm.com}
23410905Sandreas.sandberg@arm.com
23510905Sandreas.sandberg@arm.comvoid
23610905Sandreas.sandberg@arm.comSerializable::ScopedCheckpointSection::nameOut(CheckpointOut &cp)
23710905Sandreas.sandberg@arm.com{
23810905Sandreas.sandberg@arm.com    DPRINTF(Checkpoint, "ScopedCheckpointSection::nameOut: %s\n",
23910905Sandreas.sandberg@arm.com            Serializable::currentSection());
24010905Sandreas.sandberg@arm.com    cp << "\n[" << Serializable::currentSection() << "]\n";
241395SN/A}
2422SN/A
24310905Sandreas.sandberg@arm.comconst std::string &
24410905Sandreas.sandberg@arm.comSerializable::currentSection()
24510905Sandreas.sandberg@arm.com{
24610905Sandreas.sandberg@arm.com    assert(!path.empty());
24710905Sandreas.sandberg@arm.com
24810905Sandreas.sandberg@arm.com    return path.top();
24910905Sandreas.sandberg@arm.com}
250237SN/A
25110905Sandreas.sandberg@arm.comconst char *CheckpointIn::baseFilename = "m5.cpt";
2527491Ssteve.reinhardt@amd.com
25310905Sandreas.sandberg@arm.comstring CheckpointIn::currentDirectory;
2547491Ssteve.reinhardt@amd.com
2557491Ssteve.reinhardt@amd.comstring
25610905Sandreas.sandberg@arm.comCheckpointIn::setDir(const string &name)
2577491Ssteve.reinhardt@amd.com{
2587823Ssteve.reinhardt@amd.com    // use csprintf to insert curTick() into directory name if it
2597491Ssteve.reinhardt@amd.com    // appears to have a format placeholder in it.
2607491Ssteve.reinhardt@amd.com    currentDirectory = (name.find("%") != string::npos) ?
2617823Ssteve.reinhardt@amd.com        csprintf(name, curTick()) : name;
2627491Ssteve.reinhardt@amd.com    if (currentDirectory[currentDirectory.size() - 1] != '/')
2637491Ssteve.reinhardt@amd.com        currentDirectory += "/";
2647491Ssteve.reinhardt@amd.com    return currentDirectory;
2657491Ssteve.reinhardt@amd.com}
2667491Ssteve.reinhardt@amd.com
2677491Ssteve.reinhardt@amd.comstring
26810905Sandreas.sandberg@arm.comCheckpointIn::dir()
2697491Ssteve.reinhardt@amd.com{
2707491Ssteve.reinhardt@amd.com    return currentDirectory;
2717491Ssteve.reinhardt@amd.com}
2727491Ssteve.reinhardt@amd.com
27310905Sandreas.sandberg@arm.comCheckpointIn::CheckpointIn(const string &cpt_dir, SimObjectResolver &resolver)
27410453SAndrew.Bardsley@arm.com    : db(new IniFile), objNameResolver(resolver), cptDir(setDir(cpt_dir))
275237SN/A{
27610905Sandreas.sandberg@arm.com    string filename = cptDir + "/" + CheckpointIn::baseFilename;
277237SN/A    if (!db->load(filename)) {
278237SN/A        fatal("Can't load checkpoint file '%s'\n", filename);
279237SN/A    }
280237SN/A}
281237SN/A
28210905Sandreas.sandberg@arm.comCheckpointIn::~CheckpointIn()
2839086Sandreas.hansson@arm.com{
2849086Sandreas.hansson@arm.com    delete db;
2859086Sandreas.hansson@arm.com}
286237SN/A
287237SN/Abool
28811655Sandreas.sandberg@arm.comCheckpointIn::entryExists(const string &section, const string &entry)
28911655Sandreas.sandberg@arm.com{
29011655Sandreas.sandberg@arm.com    return db->entryExists(section, entry);
29111655Sandreas.sandberg@arm.com}
29211655Sandreas.sandberg@arm.com
29311655Sandreas.sandberg@arm.combool
29410905Sandreas.sandberg@arm.comCheckpointIn::find(const string &section, const string &entry, string &value)
295237SN/A{
296237SN/A    return db->find(section, entry, value);
297237SN/A}
298237SN/A
299237SN/Abool
30010905Sandreas.sandberg@arm.comCheckpointIn::findObj(const string &section, const string &entry,
3014000Ssaidi@eecs.umich.edu                    SimObject *&value)
302237SN/A{
303237SN/A    string path;
304237SN/A
305237SN/A    if (!db->find(section, entry, path))
306237SN/A        return false;
307237SN/A
30810453SAndrew.Bardsley@arm.com    value = objNameResolver.resolveSimObject(path);
3094000Ssaidi@eecs.umich.edu    return true;
310237SN/A}
311304SN/A
312304SN/Abool
31310905Sandreas.sandberg@arm.comCheckpointIn::sectionExists(const string &section)
314304SN/A{
315304SN/A    return db->sectionExists(section);
316304SN/A}
31713414Sgiacomo.travaglini@arm.com
31813414Sgiacomo.travaglini@arm.comvoid
31913414Sgiacomo.travaglini@arm.comobjParamIn(CheckpointIn &cp, const string &name, SimObject * &param)
32013414Sgiacomo.travaglini@arm.com{
32113414Sgiacomo.travaglini@arm.com    const string &section(Serializable::currentSection());
32213414Sgiacomo.travaglini@arm.com    if (!cp.findObj(section, name, param)) {
32313414Sgiacomo.travaglini@arm.com        fatal("Can't unserialize '%s:%s'\n", section, name);
32413414Sgiacomo.travaglini@arm.com    }
32513414Sgiacomo.travaglini@arm.com}
32613414Sgiacomo.travaglini@arm.com
32713414Sgiacomo.travaglini@arm.comvoid
32813414Sgiacomo.travaglini@arm.comdebug_serialize(const string &cpt_dir)
32913414Sgiacomo.travaglini@arm.com{
33013414Sgiacomo.travaglini@arm.com    Serializable::serializeAll(cpt_dir);
33113414Sgiacomo.travaglini@arm.com}
332