<commit_before>/*
 * Copyright (c) 2020-2022 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <libbio/utility/misc.hh>
#include "combine_msa.hh"

namespace lb	= libbio;
namespace vcf	= libbio::vcf;
namespace v2m	= vcf2multialign;

namespace vcf2multialign {

	void combine_msa(
		vector_type const &ref_seq,
		vector_type const &alt_seq,
		char const *variants_path,
		char const *regions_bed_path,
		char const *input_chr,
		char const *output_chr,
		std::uint16_t const ploidy,
		bool const should_output_msa_variants,
		std::ostream &os,
		bool const should_log_status
	)
	{
		v2m::vcf_record_generator gen(input_chr);
		v2m::msa_combiner combiner(output_chr, ploidy, os, should_output_msa_variants, should_log_status);

		if (variants_path)
		{
			gen.open_variants_file(variants_path, regions_bed_path);
			gen.prepare();
			gen.vcf_reader().set_parsed_fields(vcf::field::ALL);
		}
		else
		{
			gen.setup_empty_input();
		}

		auto const res(combiner.process_msa(ref_seq, alt_seq, gen));
		if (should_log_status)
		{
			lb::log_time(std::cerr)
				<< "Done. Combined variants (variant caller reverses alternative reference): " << res.combined_variants
				<< " alt eq. to ref: " << res.alt_eq_to_ref << ".\n";
		}
	}
}
<commit_msg>Improve output formatting<commit_after>/*
 * Copyright (c) 2020-2022 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <libbio/utility/misc.hh>
#include "combine_msa.hh"

namespace lb	= libbio;
namespace vcf	= libbio::vcf;
namespace v2m	= vcf2multialign;

namespace vcf2multialign {

	void combine_msa(
		vector_type const &ref_seq,
		vector_type const &alt_seq,
		char const *variants_path,
		char const *regions_bed_path,
		char const *input_chr,
		char const *output_chr,
		std::uint16_t const ploidy,
		bool const should_output_msa_variants,
		std::ostream &os,
		bool const should_log_status
	)
	{
		v2m::vcf_record_generator gen(input_chr);
		v2m::msa_combiner combiner(output_chr, ploidy, os, should_output_msa_variants, should_log_status);

		if (variants_path)
		{
			gen.open_variants_file(variants_path, regions_bed_path);
			gen.prepare();
			gen.vcf_reader().set_parsed_fields(vcf::field::ALL);
		}
		else
		{
			gen.setup_empty_input();
		}

		auto const res(combiner.process_msa(ref_seq, alt_seq, gen));
		if (should_log_status)
		{
			lb::log_time(std::cerr) << "Done.\n";
			std::cerr << "\tCombined variants (variant caller reverses alternative reference): " << res.combined_variants << '\n';
			std::cerr << "\tALT eq. to REF: " << res.alt_eq_to_ref << '\n';
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <stdio.h>
#include <stdint.h>

#include <cstdlib>

#include <unistd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <errno.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include <openssl/sha.h>

#ifdef OPENSSL_NO_SHA256
#error "SHA256 not supported!"
#endif

#include "largeblob.h"
#include "chunker.h"
#include "repo.h"

using namespace std;

/********************************************************************
 *
 *
 * LBlobEntry
 *
 *
 ********************************************************************/

LBlobEntry::LBlobEntry(const LBlobEntry &l)
    : hash(l.hash), length(l.length)
{
}

LBlobEntry::LBlobEntry(const std::string &h, uint16_t l)
    : hash(h), length(l)
{
}

LBlobEntry::~LBlobEntry()
{
}

/********************************************************************
 *
 *
 * LargeBlob
 *
 *
 ********************************************************************/

LargeBlob::LargeBlob(Repo *r)
{
    repo = r;
}

LargeBlob::~LargeBlob()
{
}

class FileChunkerCB : public ChunkerCB
{
public:
    FileChunkerCB(LargeBlob *l)
    {
	lb = l;
	lbOff = 0;
    }
    ~FileChunkerCB()
    {
    }
    int open(const string &path)
    {
	struct stat sb;

        bufLen = 8 * 1024 * 1024;
	buf = new uint8_t[bufLen];
	if (buf == NULL)
	    return -ENOMEM;

	srcFd = ::open(path.c_str(), O_RDONLY);
	if (srcFd < 0)
	    return -errno;

	if (fstat(srcFd, &sb) < 0) {
	    close(srcFd);
	    return -errno;
	}
	fileLen = sb.st_size;
        fileOff = 0;

	return 0;
    }
    virtual void match(const uint8_t *b, uint32_t l)
    {
	SHA256_CTX state;
	unsigned char hash[SHA256_DIGEST_LENGTH];
	stringstream ss;

	SHA256_Init(&state);
	SHA256_Update(&state, b, l);
	SHA256_Final(hash, &state);

	for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
	{
	    ss << hex << setw(2) << setfill('0') << (int)hash[i];
	}

        // Add the fragment into the repository
        // XXX: Journal for cleanup!
        string blob = string((const char *)b, l);
        //blob.set(b, l);
        lb->repo->addBlob(blob, Object::Blob);

        // Add the fragment to the LargeBlob object.
	lb->parts.insert(make_pair(lbOff, LBlobEntry(ss.str(), l)));
	lbOff += l;
    }
    virtual int load(uint8_t **b, uint64_t *l, uint64_t *o)
    {
        if (*b == NULL)
            *b = buf;

        if (fileOff == fileLen)
            return 0;

        // Sanity checking
        assert(*b == buf);
        assert(*l <= bufLen);
        assert(*o <= bufLen);

        if (*o != 0 || *o != *l) {
            memcpy(buf, buf + *o, *l - *o);
            *l = *l - *o;
            *o = 0;
        }

        uint64_t toRead = MIN(bufLen - *l, fileLen - fileOff);
        int status;

        status = read(srcFd, buf + *l, toRead);
        if (status < 0) {
            perror("Cannot read large file");
            assert(false);
            return -1;
        }

        fileOff += status;
        *l += status;
        *o = 0;

	return 1;
    }
private:
    // Output large blob
    LargeBlob *lb;
    uint64_t lbOff;
    // Input file
    int srcFd;
    uint64_t fileLen;
    uint64_t fileOff;
    // RK buffer
    uint8_t *buf;
    uint64_t bufLen;
};

void
LargeBlob::chunkFile(const string &path)
{
    int status;
    FileChunkerCB cb = FileChunkerCB(this);
    Chunker<4096, 2048, 8192> c = Chunker<4096, 2048, 8192>();

    status = cb.open(path);
    if (status < 0) {
	perror("Cannot open large file for chunking");
	assert(false);
	return;
    }

    c.chunk(&cb);
}

void
LargeBlob::extractFile(const string &path)
{
    int fd;
    map<uint64_t, LBlobEntry>::iterator it;

    fd = ::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
	        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (fd < 0) {
        perror("Cannot open file for writing");
        assert(false);
        return;
    }

    for (it = parts.begin(); it != parts.end(); it++)
    {
        int status;
        string tmp;

        tmp = repo->getPayload((*it).second.hash);
        assert(tmp.length() == (*it).second.length);

        status = ::write(fd, tmp.data(), tmp.length());
        if (status < 0) {
            perror("write to large object failed");
            assert(false);
            return;
        }

        assert(status == tmp.length());
    }
}

const string
LargeBlob::getBlob()
{
    string blob = "";
    map<uint64_t, LBlobEntry>::iterator it;

    for (it = parts.begin(); it != parts.end(); it++)
    {
        stringstream ss;

	blob += (*it).second.hash + " ";
        ss << (*it).second.length;
        blob += ss.str();
	blob += "\n";
    }

    return blob;
}

void
LargeBlob::fromBlob(const string &blob)
{
    uint64_t off = 0;
    string line;
    stringstream ss(blob);

    while (getline(ss, line, '\n')) {
        string hash;
        string length;
        uint64_t len;

	hash = line.substr(0, 64);
        length = line.substr(65);
        len = strtoul(length.c_str(), NULL, 10);

	parts.insert(make_pair(off, LBlobEntry(hash, len)));

        off += len;
    }
}

<commit_msg>Extra assert until we improve error handling.<commit_after>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <stdio.h>
#include <stdint.h>

#include <cstdlib>

#include <unistd.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <errno.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include <openssl/sha.h>

#ifdef OPENSSL_NO_SHA256
#error "SHA256 not supported!"
#endif

#include "largeblob.h"
#include "chunker.h"
#include "repo.h"

using namespace std;

/********************************************************************
 *
 *
 * LBlobEntry
 *
 *
 ********************************************************************/

LBlobEntry::LBlobEntry(const LBlobEntry &l)
    : hash(l.hash), length(l.length)
{
}

LBlobEntry::LBlobEntry(const std::string &h, uint16_t l)
    : hash(h), length(l)
{
}

LBlobEntry::~LBlobEntry()
{
}

/********************************************************************
 *
 *
 * LargeBlob
 *
 *
 ********************************************************************/

LargeBlob::LargeBlob(Repo *r)
{
    repo = r;
}

LargeBlob::~LargeBlob()
{
}

class FileChunkerCB : public ChunkerCB
{
public:
    FileChunkerCB(LargeBlob *l)
    {
	lb = l;
	lbOff = 0;
    }
    ~FileChunkerCB()
    {
    }
    int open(const string &path)
    {
	struct stat sb;

        bufLen = 8 * 1024 * 1024;
	buf = new uint8_t[bufLen];
	if (buf == NULL)
	    return -ENOMEM;

	srcFd = ::open(path.c_str(), O_RDONLY);
	if (srcFd < 0)
	    return -errno;

	if (fstat(srcFd, &sb) < 0) {
	    close(srcFd);
	    return -errno;
	}
	fileLen = sb.st_size;
        fileOff = 0;

	return 0;
    }
    virtual void match(const uint8_t *b, uint32_t l)
    {
	SHA256_CTX state;
	unsigned char hash[SHA256_DIGEST_LENGTH];
	stringstream ss;

	SHA256_Init(&state);
	SHA256_Update(&state, b, l);
	SHA256_Final(hash, &state);

	for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
	{
	    ss << hex << setw(2) << setfill('0') << (int)hash[i];
	}

        // Add the fragment into the repository
        // XXX: Journal for cleanup!
        string blob = string((const char *)b, l);
        //blob.set(b, l);
        lb->repo->addBlob(blob, Object::Blob);

        // Add the fragment to the LargeBlob object.
	lb->parts.insert(make_pair(lbOff, LBlobEntry(ss.str(), l)));
	lbOff += l;
    }
    virtual int load(uint8_t **b, uint64_t *l, uint64_t *o)
    {
        if (*b == NULL)
            *b = buf;

        if (fileOff == fileLen)
            return 0;

        // Sanity checking
        assert(*b == buf);
        assert(*l <= bufLen);
        assert(*o <= bufLen);

        if (*o != 0 || *o != *l) {
            memcpy(buf, buf + *o, *l - *o);
            *l = *l - *o;
            *o = 0;
        }

        uint64_t toRead = MIN(bufLen - *l, fileLen - fileOff);
        int status;

        status = read(srcFd, buf + *l, toRead);
        if (status < 0) {
            perror("Cannot read large file");
            assert(false);
            return -1;
        }
        assert(status == toRead);

        fileOff += status;
        *l += status;
        *o = 0;

	return 1;
    }
private:
    // Output large blob
    LargeBlob *lb;
    uint64_t lbOff;
    // Input file
    int srcFd;
    uint64_t fileLen;
    uint64_t fileOff;
    // RK buffer
    uint8_t *buf;
    uint64_t bufLen;
};

void
LargeBlob::chunkFile(const string &path)
{
    int status;
    FileChunkerCB cb = FileChunkerCB(this);
    Chunker<4096, 2048, 8192> c = Chunker<4096, 2048, 8192>();

    status = cb.open(path);
    if (status < 0) {
	perror("Cannot open large file for chunking");
	assert(false);
	return;
    }

    c.chunk(&cb);
}

void
LargeBlob::extractFile(const string &path)
{
    int fd;
    map<uint64_t, LBlobEntry>::iterator it;

    fd = ::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
	        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (fd < 0) {
        perror("Cannot open file for writing");
        assert(false);
        return;
    }

    for (it = parts.begin(); it != parts.end(); it++)
    {
        int status;
        string tmp;

        tmp = repo->getPayload((*it).second.hash);
        assert(tmp.length() == (*it).second.length);

        status = ::write(fd, tmp.data(), tmp.length());
        if (status < 0) {
            perror("write to large object failed");
            assert(false);
            return;
        }

        assert(status == tmp.length());
    }
}

const string
LargeBlob::getBlob()
{
    string blob = "";
    map<uint64_t, LBlobEntry>::iterator it;

    for (it = parts.begin(); it != parts.end(); it++)
    {
        stringstream ss;

	blob += (*it).second.hash + " ";
        ss << (*it).second.length;
        blob += ss.str();
	blob += "\n";
    }

    return blob;
}

void
LargeBlob::fromBlob(const string &blob)
{
    uint64_t off = 0;
    string line;
    stringstream ss(blob);

    while (getline(ss, line, '\n')) {
        string hash;
        string length;
        uint64_t len;

	hash = line.substr(0, 64);
        length = line.substr(65);
        len = strtoul(length.c_str(), NULL, 10);

	parts.insert(make_pair(off, LBlobEntry(hash, len)));

        off += len;
    }
}

<|endoftext|>


<commit_before>/*
    This file is part of the Tortoise Plugin for Retroshare.

    Tortoise is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tortoise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Tortoise.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "p3TortoiseRS.h"
#include "RSTortoiseItems.h"

#include "pqi/p3linkmgr.h"
#include "retroshare/rsturtle.h"

#include <iostream>

p3TortoiseRS::p3TortoiseRS(RsPluginHandler *pgHandler, RsPeers* peers ) :
        m_peers(peers)
{
    m_hash = "";
    m_Turtle = static_cast< p3turtle* >( rsTurtle );
    m_Turtle->registerTunnelService(this);
}

void p3TortoiseRS::addMonitor(const std::string & hash )
{
    std::cerr << "Tortoise: Monitoring tunnels for hash " << hash << std::endl;
    m_Turtle->monitorTunnels( hash, this ) ;
}

void p3TortoiseRS::setListener(const std::string & hash )
{
    std::cerr << "Tortoise: Listening to hash " << hash << std::endl;
    m_hash = hash;
}

void p3TortoiseRS::sendMessage(const std::string & message )
{
    for( std::set< std::string>::const_iterator it = m_vPeerList.begin(); it != m_vPeerList.end(); it++ ){
        m_Turtle->sendTurtleData( *it, new TortoiseItem( message ) );
    }
}

// implemented from the Turtle interface
// do not use any of these functions as a convenient place to call turtle functions
// like sending a message. This will result in a deadlock

void p3TortoiseRS::addVirtualPeer( const TurtleFileHash& hash,const TurtleVirtualPeerId & virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir )
{
    std::cerr << "Tortoise:  Adding virtual peer " << virtual_peer_id << " for hash " << hash << "  --  Direction " << dir << std::endl;
    m_vPeerList.insert( virtual_peer_id );
}

void p3TortoiseRS::removeVirtualPeer( const TurtleFileHash& hash,const TurtleVirtualPeerId & virtual_peer_id )
{
    std::cerr << "Tortoise:  Removing virtual peer " << virtual_peer_id << " for hash " << hash << std::endl;
    m_vPeerList.erase( virtual_peer_id );
}

void p3TortoiseRS::receiveTurtleData( RsTurtleGenericTunnelItem * item,const std::string& hash,const std::string & virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction )
{
    std::cerr << "Tortoise:  Received Data from Turtle router" << std::endl;
    item->print( std::cerr );
}

bool p3TortoiseRS::handleTunnelRequest(const std::string & hash, const std::string & peer_id)
{
    if( hash == m_hash ){
        std::cerr << "Tortoise: Handling tunnel request: hash: " << hash << " -- ID: " << peer_id << std::endl;
        return true;
    }
    else{
        std::cerr << "Tortoise: NOT handling tunnel request: hash: " << hash << " -- ID: " << peer_id << std::endl;
        return false;
    }
}

RsTurtleGenericTunnelItem * p3TortoiseRS::deserialiseItem(void * data, uint32_t pktsize) const
{
    std::cerr << "Tortoise: Attempting  to deserialise Item" << std::endl;

    /* get the type and size */
    uint32_t rstype = getRsItemId(data);

    try{
        switch(getRsItemSubType(rstype))
        {
        case TortoiseItem::TORTOISE_ITEM:
        {
             TortoiseItem * tortoiseItem = new TortoiseItem(data, pktsize);
             tortoiseItem->print( std::cerr );
             return tortoiseItem;
        }
        default:
            return NULL;
        }
    }
    catch(std::exception& e){
        std::cerr << "RsTortoiseSerialiser: deserialization error: " << e.what() << std::endl;
        return NULL;
    }
}
<commit_msg>remove debug code<commit_after>/*
    This file is part of the Tortoise Plugin for Retroshare.

    Tortoise is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tortoise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Tortoise.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "p3TortoiseRS.h"
#include "RSTortoiseItems.h"

#include "pqi/p3linkmgr.h"
#include "retroshare/rsturtle.h"

#include <iostream>

p3TortoiseRS::p3TortoiseRS(RsPluginHandler *pgHandler, RsPeers* peers ) :
        m_peers(peers)
{
    m_hash = "";
    m_Turtle = static_cast< p3turtle* >( rsTurtle );
    m_Turtle->registerTunnelService(this);
}

void p3TortoiseRS::addMonitor(const std::string & hash )
{
    std::cerr << "Tortoise: Monitoring tunnels for hash " << hash << std::endl;
    m_Turtle->monitorTunnels( hash, this ) ;
}

void p3TortoiseRS::setListener(const std::string & hash )
{
    std::cerr << "Tortoise: Listening to hash " << hash << std::endl;
    m_hash = hash;
}

void p3TortoiseRS::sendMessage(const std::string & message )
{
    for( std::set< std::string>::const_iterator it = m_vPeerList.begin(); it != m_vPeerList.end(); it++ ){
        m_Turtle->sendTurtleData( *it, new TortoiseItem( message ) );
    }
}

// implemented from the Turtle interface
// do not use any of these functions as a convenient place to call turtle functions
// like sending a message. This will result in a deadlock

void p3TortoiseRS::addVirtualPeer( const TurtleFileHash& hash,const TurtleVirtualPeerId & virtual_peer_id,RsTurtleGenericTunnelItem::Direction dir )
{
    std::cerr << "Tortoise:  Adding virtual peer " << virtual_peer_id << " for hash " << hash << "  --  Direction " << dir << std::endl;
    m_vPeerList.insert( virtual_peer_id );
}

void p3TortoiseRS::removeVirtualPeer( const TurtleFileHash& hash,const TurtleVirtualPeerId & virtual_peer_id )
{
    std::cerr << "Tortoise:  Removing virtual peer " << virtual_peer_id << " for hash " << hash << std::endl;
    m_vPeerList.erase( virtual_peer_id );
}

void p3TortoiseRS::receiveTurtleData( RsTurtleGenericTunnelItem * item,const std::string& hash,const std::string & virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction )
{
    std::cerr << "Tortoise:  Received Data from Turtle router" << std::endl;
    item->print( std::cerr );
}

bool p3TortoiseRS::handleTunnelRequest(const std::string & hash, const std::string & peer_id)
{
    if( hash == m_hash ){
        std::cerr << "Tortoise: Handling tunnel request: hash: " << hash << " -- ID: " << peer_id << std::endl;
        return true;
    }
    else{
        std::cerr << "Tortoise: NOT handling tunnel request: hash: " << hash << " -- ID: " << peer_id << std::endl;
        return false;
    }
}

RsTurtleGenericTunnelItem * p3TortoiseRS::deserialiseItem(void * data, uint32_t pktsize) const
{
    std::cerr << "Tortoise: Attempting  to deserialise Item" << std::endl;

    /* get the type and size */
    uint32_t rstype = getRsItemId(data);

    try{
        switch(getRsItemSubType(rstype))
        {
        case TortoiseItem::TORTOISE_ITEM:
             return new TortoiseItem(data, pktsize);
        default:
            return NULL;
        }
    }
    catch(std::exception& e){
        std::cerr << "RsTortoiseSerialiser: deserialization error: " << e.what() << std::endl;
        return NULL;
    }
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  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.txt
 *
 *  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 "rtkReg23ProjectionGeometry.h"

//std
#include <math.h>
//ITK
#include <itkVector.h>
#include <itkEuler3DTransform.h>

rtk::Reg23ProjectionGeometry::Reg23ProjectionGeometry()
  : rtk::ThreeDCircularProjectionGeometry()
{
}

rtk::Reg23ProjectionGeometry::~Reg23ProjectionGeometry()
{
}

bool rtk::Reg23ProjectionGeometry::VerifyAngles(const double outOfPlaneAngleRAD,
  const double gantryAngleRAD, const double inPlaneAngleRAD,
  const Matrix3x3Type &referenceMatrix) const
{
  typedef itk::Euler3DTransform<double> EulerType;

  const Matrix3x3Type &rm = referenceMatrix; // shortcut
  const double EPSILON = 1e-6; // internal tolerance for comparison

  EulerType::Pointer euler = EulerType::New();
  euler->SetComputeZYX(false); // ZXY order
  euler->SetRotation(outOfPlaneAngleRAD, gantryAngleRAD, inPlaneAngleRAD);
  Matrix3x3Type m = euler->GetMatrix(); // resultant matrix

  for (int i = 0; i < 3; i++) // check whether matrices match
    for (int j = 0; j < 3; j++)
      if (fabs(rm[i][j] - m[i][j]) > EPSILON)
        return false;

  return true;
}

bool rtk::Reg23ProjectionGeometry::FixAngles(double &outOfPlaneAngleRAD,
  double &gantryAngleRAD, double &inPlaneAngleRAD,
  const Matrix3x3Type &referenceMatrix) const
{
  const Matrix3x3Type &rm = referenceMatrix; // shortcut
  const double EPSILON = 1e-6; // internal tolerance for comparison

  if (fabs(fabs(rm[2][0]) - 1.) > EPSILON)
  {
    double oa, ga, ia;

    // @see Slabaugh, GG, "Computing Euler angles from a rotation matrix"

    // first trial:
    oa = asin(rm[2][1]);
    double coa = cos(oa);
    ga = atan2(-rm[2][0] / coa, rm[2][2] / coa);
    ia = atan2(-rm[0][1] / coa, rm[1][1] / coa);
    if (VerifyAngles(oa, ga, ia, rm))
    {
      outOfPlaneAngleRAD = oa;
      gantryAngleRAD = ga;
      inPlaneAngleRAD = ia;
      return true;
    }

    // second trial:
    oa = 3.1415926535897932384626433832795 /*PI*/ - asin(rm[2][1]);
    coa = cos(oa);
    ga = atan2(-rm[2][0] / coa, rm[2][2] / coa);
    ia = atan2(-rm[0][1] / coa, rm[1][1] / coa);
    if (VerifyAngles(oa, ga, ia, rm))
    {
      outOfPlaneAngleRAD = oa;
      gantryAngleRAD = ga;
      inPlaneAngleRAD = ia;
      return true;
    }

    return false;
  }
  return false;
}

bool rtk::Reg23ProjectionGeometry::AddReg23Projection(
    const PointType &sourcePosition, const PointType &detectorPosition,
    const VectorType &detectorRowVector, const VectorType &detectorColumnVector)
{
  typedef itk::Euler3DTransform<double> EulerType;

  // these parameters relate absolutely to the WCS (IEC-based):
  const VectorType &r = detectorRowVector; // row dir
  const VectorType &c = detectorColumnVector; // column dir
  VectorType n = itk::CrossProduct(r, c); // normal
  const PointType &S = sourcePosition; // source pos
  const PointType &R = detectorPosition; // detector pos

  if (fabs(r * c) > 1e-6) // non-orthogonal row/column vectors
    return false;

  // Euler angles (ZXY convention) from detector orientation in IEC-based WCS:
  double ga; // gantry angle
  double oa; // out-of-plane angle
  double ia; // in-plane angle
  // extract Euler angles from the orthogonal matrix which is established
  // by the detector orientation; however, we would like RTK to internally
  // store the inverse of this rotation matrix, therefore the corresponding
  // angles are computed here:
  Matrix3x3Type rm; // reference matrix
  // NOTE: This transposed matrix should internally
  // set by rtk::ThreeDProjectionGeometry (inverse)
  // of external rotation!
  rm[0][0] = r[0]; rm[0][1] = r[1]; rm[0][2] = r[2];
  rm[1][0] = c[0]; rm[1][1] = c[1]; rm[1][2] = c[2];
  rm[2][0] = n[0]; rm[2][1] = n[1]; rm[2][2] = n[2];
  // extract Euler angles by using the standard ITK implementation:
  EulerType::Pointer euler = EulerType::New();
  euler->SetComputeZYX(false); // ZXY order
  // workaround: Orthogonality tolerance problem when using
  // Euler3DTransform->SetMatrix() due to error magnification.
  // Parent class MatrixOffsetTransformBase does not perform an
  // orthogonality check on the matrix!
  euler->itk::MatrixOffsetTransformBase<double>::SetMatrix(rm);
  oa = euler->GetAngleX(); // delivers radians
  ga = euler->GetAngleY();
  ia = euler->GetAngleZ();
  // verify that extracted ZXY angles result in the *desired* matrix:
  // (at some angle constellations we may run into numerical troubles, therefore,
  // verify angles and try to fix instabilities)
  if (!VerifyAngles(oa, ga, ia, rm))
  {
    if (!FixAngles(oa, ga, ia, rm))
      return false;
  }
  // since rtk::ThreeDCircularProjectionGeometry::AddProjection() mirrors the
  // angles (!) internally, let's invert the computed ones in order to
  // get at the end what we would like (see above); convert rad->deg:
  ga *= -57.29577951308232;
  oa *= -57.29577951308232;
  ia *= -57.29577951308232;

  // SID: distance from source to isocenter along detector normal
  double SID = n[0] * S[0] + n[1] * S[1] + n[2] * S[2];
  // SDD: distance from source to detector along detector normal
  double SDD = n[0] * (S[0] - R[0]) + n[1] * (S[1] - R[1]) + n[2] * (S[2] - R[2]);
  if (fabs(SDD) < 1e-6) // source is in detector plane
    return false;

  // source offset: compute source's "in-plane" x/y shift off isocenter
  VectorType Sv;
  Sv[0] = S[0];
  Sv[1] = S[1];
  Sv[2] = S[2];
  double oSx = Sv * r;
  double oSy = Sv * c;

  // detector offset: compute detector's in-plane x/y shift off isocenter
  VectorType Rv;
  Rv[0] = R[0];
  Rv[1] = R[1];
  Rv[2] = R[2];
  double oRx = Rv * r;
  double oRy = Rv * c;

  // configure native RTK geometry
  this->Superclass::AddProjection(SID, SDD, ga, oRx, oRy, oa, ia, oSx, oSy);

  return true;
}
<commit_msg>Handle NaN in the verification of angles<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  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.txt
 *
 *  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 "rtkReg23ProjectionGeometry.h"

//std
#include <math.h>
//ITK
#include <itkVector.h>
#include <itkEuler3DTransform.h>

rtk::Reg23ProjectionGeometry::Reg23ProjectionGeometry()
  : rtk::ThreeDCircularProjectionGeometry()
{
}

rtk::Reg23ProjectionGeometry::~Reg23ProjectionGeometry()
{
}

bool rtk::Reg23ProjectionGeometry::VerifyAngles(const double outOfPlaneAngleRAD,
  const double gantryAngleRAD, const double inPlaneAngleRAD,
  const Matrix3x3Type &referenceMatrix) const
{
  // Check if parameters are Nan. Fails if they are.
  if(outOfPlaneAngleRAD != outOfPlaneAngleRAD ||
     gantryAngleRAD != gantryAngleRAD ||
     inPlaneAngleRAD != inPlaneAngleRAD)
    return false;

  typedef itk::Euler3DTransform<double> EulerType;

  const Matrix3x3Type &rm = referenceMatrix; // shortcut
  const double EPSILON = 1e-6; // internal tolerance for comparison

  EulerType::Pointer euler = EulerType::New();
  euler->SetComputeZYX(false); // ZXY order
  euler->SetRotation(outOfPlaneAngleRAD, gantryAngleRAD, inPlaneAngleRAD);
  Matrix3x3Type m = euler->GetMatrix(); // resultant matrix

  for (int i = 0; i < 3; i++) // check whether matrices match
    for (int j = 0; j < 3; j++)
      if (fabs(rm[i][j] - m[i][j]) > EPSILON)
        return false;

  return true;
}

bool rtk::Reg23ProjectionGeometry::FixAngles(double &outOfPlaneAngleRAD,
  double &gantryAngleRAD, double &inPlaneAngleRAD,
  const Matrix3x3Type &referenceMatrix) const
{
  const Matrix3x3Type &rm = referenceMatrix; // shortcut
  const double EPSILON = 1e-6; // internal tolerance for comparison

  if (fabs(fabs(rm[2][0]) - 1.) > EPSILON)
  {
    double oa, ga, ia;

    // @see Slabaugh, GG, "Computing Euler angles from a rotation matrix"

    // first trial:
    oa = asin(rm[2][1]);
    double coa = cos(oa);
    ga = atan2(-rm[2][0] / coa, rm[2][2] / coa);
    ia = atan2(-rm[0][1] / coa, rm[1][1] / coa);
    if (VerifyAngles(oa, ga, ia, rm))
    {
      outOfPlaneAngleRAD = oa;
      gantryAngleRAD = ga;
      inPlaneAngleRAD = ia;
      return true;
    }

    // second trial:
    oa = 3.1415926535897932384626433832795 /*PI*/ - asin(rm[2][1]);
    coa = cos(oa);
    ga = atan2(-rm[2][0] / coa, rm[2][2] / coa);
    ia = atan2(-rm[0][1] / coa, rm[1][1] / coa);
    if (VerifyAngles(oa, ga, ia, rm))
    {
      outOfPlaneAngleRAD = oa;
      gantryAngleRAD = ga;
      inPlaneAngleRAD = ia;
      return true;
    }

    return false;
  }
  return false;
}

bool rtk::Reg23ProjectionGeometry::AddReg23Projection(
    const PointType &sourcePosition, const PointType &detectorPosition,
    const VectorType &detectorRowVector, const VectorType &detectorColumnVector)
{
  typedef itk::Euler3DTransform<double> EulerType;

  // these parameters relate absolutely to the WCS (IEC-based):
  const VectorType &r = detectorRowVector; // row dir
  const VectorType &c = detectorColumnVector; // column dir
  VectorType n = itk::CrossProduct(r, c); // normal
  const PointType &S = sourcePosition; // source pos
  const PointType &R = detectorPosition; // detector pos

  if (fabs(r * c) > 1e-6) // non-orthogonal row/column vectors
    return false;

  // Euler angles (ZXY convention) from detector orientation in IEC-based WCS:
  double ga; // gantry angle
  double oa; // out-of-plane angle
  double ia; // in-plane angle
  // extract Euler angles from the orthogonal matrix which is established
  // by the detector orientation; however, we would like RTK to internally
  // store the inverse of this rotation matrix, therefore the corresponding
  // angles are computed here:
  Matrix3x3Type rm; // reference matrix
  // NOTE: This transposed matrix should internally
  // set by rtk::ThreeDProjectionGeometry (inverse)
  // of external rotation!
  rm[0][0] = r[0]; rm[0][1] = r[1]; rm[0][2] = r[2];
  rm[1][0] = c[0]; rm[1][1] = c[1]; rm[1][2] = c[2];
  rm[2][0] = n[0]; rm[2][1] = n[1]; rm[2][2] = n[2];
  // extract Euler angles by using the standard ITK implementation:
  EulerType::Pointer euler = EulerType::New();
  euler->SetComputeZYX(false); // ZXY order
  // workaround: Orthogonality tolerance problem when using
  // Euler3DTransform->SetMatrix() due to error magnification.
  // Parent class MatrixOffsetTransformBase does not perform an
  // orthogonality check on the matrix!
  euler->itk::MatrixOffsetTransformBase<double>::SetMatrix(rm);
  oa = euler->GetAngleX(); // delivers radians
  ga = euler->GetAngleY();
  ia = euler->GetAngleZ();
  // verify that extracted ZXY angles result in the *desired* matrix:
  // (at some angle constellations we may run into numerical troubles, therefore,
  // verify angles and try to fix instabilities)
  if (!VerifyAngles(oa, ga, ia, rm))
  {
    if (!FixAngles(oa, ga, ia, rm))
      return false;
  }
  // since rtk::ThreeDCircularProjectionGeometry::AddProjection() mirrors the
  // angles (!) internally, let's invert the computed ones in order to
  // get at the end what we would like (see above); convert rad->deg:
  ga *= -57.29577951308232;
  oa *= -57.29577951308232;
  ia *= -57.29577951308232;

  // SID: distance from source to isocenter along detector normal
  double SID = n[0] * S[0] + n[1] * S[1] + n[2] * S[2];
  // SDD: distance from source to detector along detector normal
  double SDD = n[0] * (S[0] - R[0]) + n[1] * (S[1] - R[1]) + n[2] * (S[2] - R[2]);
  if (fabs(SDD) < 1e-6) // source is in detector plane
    return false;

  // source offset: compute source's "in-plane" x/y shift off isocenter
  VectorType Sv;
  Sv[0] = S[0];
  Sv[1] = S[1];
  Sv[2] = S[2];
  double oSx = Sv * r;
  double oSy = Sv * c;

  // detector offset: compute detector's in-plane x/y shift off isocenter
  VectorType Rv;
  Rv[0] = R[0];
  Rv[1] = R[1];
  Rv[2] = R[2];
  double oRx = Rv * r;
  double oRy = Rv * c;

  // configure native RTK geometry
  this->Superclass::AddProjection(SID, SDD, ga, oRx, oRy, oa, ia, oSx, oSy);

  return true;
}
<|endoftext|>


<commit_before>#include "protect.h"

int main(int argc, char* argv[])
{
	ros::init(argc, argv, "Anti_collision_node");

	protector protectObj;

	ros::Rate loop_rate(10);

	int delay_cnt = 0;
	float coli_prob = 0.0;

	ofstream  file1;
	file1.open ("laser.txt");

	ROS_INFO("Start to detect the safety...");

	while (ros::ok())
	{
		if(delay_cnt < DELAY_CNT_MAX)
		{
			delay_cnt++;
			ros::spinOnce();
			loop_rate.sleep();
		}

		if(delay_cnt >= DELAY_CNT_MAX)
		{
			protectObj.CalcMinDis4LaserScan(protectObj.scan4safty);
			protectObj.CalcMinDis4Ultrosonic(protectObj.ultra_vec);

			cout<<"protectObj.min_scan: "<< protectObj.min_scan << endl;
			cout<<"protectObj.min_index_scan: "<< protectObj.min_index_scan<< endl;
			cout<<"protectObj.min_scan_angle: "<< protectObj.min_scan_angle<< endl;
			cout<<"protectObj.laser_prob: "<< protectObj.laser_unsafe_prob<< endl;

			for(int j = 1; j <= SCAN4SAFE_NUM; j++)
			{
				file1<< fixed << setprecision(4) << protectObj.scan4safty[j];
				file1 << '\t';
			}

			file1.close();
			coli_prob = protectObj.IntegrateMultiInfo4Safety(&protectObj.advise_action);
			cout<<"coli_prob: "<< coli_prob<< endl;

			float linear_vel_safe = 0.0;
			float angular_vel_safe = 0.0;
			int steer = 0;
			protectObj.CalcLaserSafeVelThd(protectObj.min_scan , protectObj.min_scan_angle, steer, &linear_vel_safe, &angular_vel_safe);
			cout<<"linear_vel_safe: "<< linear_vel_safe<< endl;
			cout<<"angular_vel_safe: "<< angular_vel_safe<< endl;

			protectObj.Intg4EnvSecure();
			protectObj.security_pub4env.publish(protectObj.env_secure);

			protectObj.safe_vel.header.stamp = ros::Time::now();
			protectObj.safe_vel.header.frame_id = "robot";

			protectObj.safe_vel.stop.data = true;
			protectObj.safe_vel.linear_safe_thd = linear_vel_safe;
			protectObj.safe_vel.linear_safe_vel = 0.0;
			protectObj.safe_vel.steer = steer;
			protectObj.safe_vel.angular_safe_thd = angular_vel_safe;
			protectObj.safe_vel.angular_safe_vel = 0.0;
			protectObj.security_pub4nav.publish(protectObj.safe_vel);

			ros::spinOnce();
			loop_rate.sleep();
			ROS_INFO("end ...");
		}

	}

	return 0;
}

<commit_msg>modify the safe stop conditions<commit_after>#include "protect.h"

int main(int argc, char* argv[])
{
	ros::init(argc, argv, "Anti_collision_node");

	protector protectObj;

	ros::Rate loop_rate(10);

	int delay_cnt = 0;
	float coli_prob = 0.0;

	ofstream  file1;
	file1.open ("laser.txt");

	ROS_INFO("Start to detect the safety...");

	while (ros::ok())
	{
		if(delay_cnt < DELAY_CNT_MAX)
		{
			delay_cnt++;
			ros::spinOnce();
			loop_rate.sleep();
		}

		if(delay_cnt >= DELAY_CNT_MAX)
		{
			protectObj.CalcMinDis4LaserScan(protectObj.scan4safty);
			protectObj.CalcMinDis4Ultrosonic(protectObj.ultra_vec);

			cout<<"protectObj.min_scan: "<< protectObj.min_scan << endl;
			cout<<"protectObj.min_index_scan: "<< protectObj.min_index_scan<< endl;
			cout<<"protectObj.min_scan_angle: "<< protectObj.min_scan_angle<< endl;
			cout<<"protectObj.laser_prob: "<< protectObj.laser_unsafe_prob<< endl;

			for(int j = 1; j <= SCAN4SAFE_NUM; j++)
			{
				file1<< fixed << setprecision(4) << protectObj.scan4safty[j];
				file1 << '\t';
			}

			file1.close();
			coli_prob = protectObj.IntegrateMultiInfo4Safety(&protectObj.advise_action);
			cout<<"coli_prob: "<< coli_prob<< endl;

			float linear_vel_safe = 0.0;
			float angular_vel_safe = 0.0;
			int steer = 0;
			protectObj.CalcLaserSafeVelThd(protectObj.min_scan , protectObj.min_scan_angle, steer, &linear_vel_safe, &angular_vel_safe);
			cout<<"linear_vel_safe: "<< linear_vel_safe<< endl;
			cout<<"angular_vel_safe: "<< angular_vel_safe<< endl;

			protectObj.Intg4EnvSecure();
			protectObj.security_pub4env.publish(protectObj.env_secure);

			protectObj.safe_vel.header.stamp = ros::Time::now();
			protectObj.safe_vel.header.frame_id = "robot";

			if((linear_vel_safe == LINEAR_STOP) && (angular_vel_safe == ANGULAR_STOP) && (steer == 0))
			{
				protectObj.safe_vel.stop.data = true;
			}
			else
			{
				protectObj.safe_vel.stop.data = false;
			}

			protectObj.safe_vel.linear_safe_thd = linear_vel_safe;
			protectObj.safe_vel.linear_safe_vel = 0.0;
			protectObj.safe_vel.steer = steer;
			protectObj.safe_vel.angular_safe_thd = angular_vel_safe;
			protectObj.safe_vel.angular_safe_vel = 0.0;
			protectObj.security_pub4nav.publish(protectObj.safe_vel);

			ros::spinOnce();
			loop_rate.sleep();
			ROS_INFO("end ...");
		}

	}

	return 0;
}

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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 "taskschedulertbb.h"

namespace embree
{
  static bool g_tbb_threads_initialized = false;
  static tbb::task_scheduler_init g_tbb_threads(tbb::task_scheduler_init::deferred);

  class TBBAffinity: public tbb::task_scheduler_observer
  {
    tbb::atomic<int> threadCount;

  public:
    TBBAffinity() {
      threadCount = 0;
    }

    void on_scheduler_entry( bool )
    {
      ++threadCount;
      setAffinity(TaskScheduler::threadIndex());
    }

    void on_scheduler_exit( bool ) {
      --threadCount;
    }

  } tbb_affinity;

  void TaskScheduler::create(size_t numThreads, bool set_affinity, bool start_threads)
  {
    assert(numThreads);

    /* first terminate threads in case we configured them */
    if (g_tbb_threads_initialized) {
      g_tbb_threads.terminate();
      g_tbb_threads_initialized = false;
    }

    /* only set affinity if requested by the user */
    if (set_affinity)
      tbb_affinity.observe(true);

    /* now either keep default settings or configure number of threads */
    if (numThreads == std::numeric_limits<size_t>::max()) {
      g_tbb_threads_initialized = false;
      numThreads = threadCount();
      //numThreads = tbb::task_scheduler_init::default_num_threads();
    } else {
      g_tbb_threads_initialized = true;
      const int max_concurrency = threadCount();
      if (numThreads > max_concurrency) numThreads = max_concurrency;
      g_tbb_threads.initialize(int(numThreads));
    }

    /* start worker threads */
    if (start_threads)
    {
      BarrierSys barrier(numThreads);
      tbb::parallel_for(size_t(0), size_t(numThreads), size_t(1), [&] ( size_t i ) {
          barrier.wait();
        });
    }
  }

  void TaskScheduler::destroy()
  {
    if (g_tbb_threads_initialized) {
      g_tbb_threads.terminate();
      g_tbb_threads_initialized = false;
    }
  }
}
<commit_msg>bugfix in setting TBB thread affinity for old TBB versions<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// 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 "taskschedulertbb.h"

namespace embree
{
  static bool g_tbb_threads_initialized = false;
  static tbb::task_scheduler_init g_tbb_threads(tbb::task_scheduler_init::deferred);

  class TBBAffinity: public tbb::task_scheduler_observer
  {
    tbb::atomic<int> threadCount;

  public:
    TBBAffinity() {
      threadCount = 0;
    }

    void on_scheduler_entry( bool )
    {
      const int threadIndex = threadCount++;
      setAffinity(threadIndex); // do not use TaskScheduler::threadIndex() as old TBB versions to not have that function
    }

    void on_scheduler_exit( bool ) {
      threadCount--;
    }

  } tbb_affinity;

  void TaskScheduler::create(size_t numThreads, bool set_affinity, bool start_threads)
  {
    assert(numThreads);

    /* first terminate threads in case we configured them */
    if (g_tbb_threads_initialized) {
      g_tbb_threads.terminate();
      g_tbb_threads_initialized = false;
    }

    /* only set affinity if requested by the user */
    if (set_affinity)
      tbb_affinity.observe(true);

    /* now either keep default settings or configure number of threads */
    if (numThreads == std::numeric_limits<size_t>::max()) {
      g_tbb_threads_initialized = false;
      numThreads = threadCount();
      //numThreads = tbb::task_scheduler_init::default_num_threads();
    } else {
      g_tbb_threads_initialized = true;
      const int max_concurrency = threadCount();
      if (numThreads > max_concurrency) numThreads = max_concurrency;
      g_tbb_threads.initialize(int(numThreads));
    }

    /* start worker threads */
    if (start_threads)
    {
      BarrierSys barrier(numThreads);
      tbb::parallel_for(size_t(0), size_t(numThreads), size_t(1), [&] ( size_t i ) {
          barrier.wait();
        });
    }
  }

  void TaskScheduler::destroy()
  {
    if (g_tbb_threads_initialized) {
      g_tbb_threads.terminate();
      g_tbb_threads_initialized = false;
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2001-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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 COPYRIGHT
 * OWNER 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.
 *
 * Authors: Ron Dreslinski
 *          Ali Saidi
 */

#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <zlib.h>

#include <iostream>
#include <string>

#include "arch/isa_traits.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
#include "mem/physical.hh"
#include "sim/builder.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"

using namespace std;
using namespace TheISA;

PhysicalMemory::PhysicalMemory(Params *p)
    : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
{
    if (params()->addrRange.size() % TheISA::PageBytes != 0)
        panic("Memory Size not divisible by page size\n");

    int map_flags = MAP_ANON | MAP_PRIVATE;
    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                map_flags, -1, 0);

    if (pmemAddr == (void *)MAP_FAILED) {
        perror("mmap");
        fatal("Could not mmap!\n");
    }

    //If requested, initialize all the memory to 0
    if(params()->zero)
        memset(pmemAddr, 0, params()->addrRange.size());

    pagePtr = 0;
}

void
PhysicalMemory::init()
{
    if (!port)
        panic("PhysicalMemory not connected to anything!");
    port->sendStatusChange(Port::RangeChange);
}

PhysicalMemory::~PhysicalMemory()
{
    if (pmemAddr)
        munmap(pmemAddr, params()->addrRange.size());
    //Remove memPorts?
}

Addr
PhysicalMemory::new_page()
{
    Addr return_addr = pagePtr << LogVMPageSize;
    return_addr += params()->addrRange.start;

    ++pagePtr;
    return return_addr;
}

int
PhysicalMemory::deviceBlockSize()
{
    //Can accept anysize request
    return 0;
}

Tick
PhysicalMemory::calculateLatency(PacketPtr pkt)
{
    return lat;
}

// Add load-locked to tracking list.  Should only be called if the
// operation is a load and the LOCKED flag is set.
void
PhysicalMemory::trackLoadLocked(Request *req)
{
    Addr paddr = LockedAddr::mask(req->getPaddr());

    // first we check if we already have a locked addr for this
    // xc.  Since each xc only gets one, we just update the
    // existing record with the new address.
    list<LockedAddr>::iterator i;

    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
        if (i->matchesContext(req)) {
            DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
                    req->getCpuNum(), req->getThreadNum(), paddr);
            i->addr = paddr;
            return;
        }
    }

    // no record for this xc: need to allocate a new one
    DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
            req->getCpuNum(), req->getThreadNum(), paddr);
    lockedAddrList.push_front(LockedAddr(req));
}

// Called on *writes* only... both regular stores and
// store-conditional operations.  Check for conventional stores which
// conflict with locked addresses, and for success/failure of store
// conditionals.
bool
PhysicalMemory::checkLockedAddrList(Request *req)
{
    Addr paddr = LockedAddr::mask(req->getPaddr());
    bool isLocked = req->isLocked();

    // Initialize return value.  Non-conditional stores always
    // succeed.  Assume conditional stores will fail until proven
    // otherwise.
    bool success = !isLocked;

    // Iterate over list.  Note that there could be multiple matching
    // records, as more than one context could have done a load locked
    // to this location.
    list<LockedAddr>::iterator i = lockedAddrList.begin();

    while (i != lockedAddrList.end()) {

        if (i->addr == paddr) {
            // we have a matching address

            if (isLocked && i->matchesContext(req)) {
                // it's a store conditional, and as far as the memory
                // system can tell, the requesting context's lock is
                // still valid.
                DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
                        req->getCpuNum(), req->getThreadNum(), paddr);
                success = true;
            }

            // Get rid of our record of this lock and advance to next
            DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
                    i->cpuNum, i->threadNum, paddr);
            i = lockedAddrList.erase(i);
        }
        else {
            // no match: advance to next record
            ++i;
        }
    }

    if (isLocked) {
        req->setScResult(success ? 1 : 0);
    }

    return success;
}

void
PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
{
    assert(pkt->getAddr() >= params()->addrRange.start &&
           pkt->getAddr() + pkt->getSize() <= params()->addrRange.start +
           params()->addrRange.size());

    if (pkt->isRead()) {
        if (pkt->req->isLocked()) {
            trackLoadLocked(pkt->req);
        }
        DPRINTF(MemoryAccess, "Performing Read of size %i on address 0x%x\n",
                pkt->getSize(), pkt->getAddr());
        memcpy(pkt->getPtr<uint8_t>(),
               pmemAddr + pkt->getAddr() - params()->addrRange.start,
               pkt->getSize());
    }
    else if (pkt->isWrite()) {
        if (writeOK(pkt->req)) {
            DPRINTF(MemoryAccess, "Performing Write of size %i on address 0x%x\n",
                    pkt->getSize(), pkt->getAddr());
            memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
                   pkt->getPtr<uint8_t>(), pkt->getSize());
        }
    }
    else if (pkt->isInvalidate()) {
        //upgrade or invalidate
        pkt->flags |= SATISFIED;
    }
    else {
        panic("unimplemented");
    }

    pkt->result = Packet::Success;
}

Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
{
    if (if_name == "port" && idx == -1) {
        if (port != NULL)
           panic("PhysicalMemory::getPort: additional port requested to memory!");
        port = new MemoryPort(name() + "-port", this);
        return port;
    } else if (if_name == "functional") {
        /* special port for functional writes at startup. And for memtester */
        return new MemoryPort(name() + "-funcport", this);
    } else {
        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
    }
}

void
PhysicalMemory::recvStatusChange(Port::Status status)
{
}

PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
                                       PhysicalMemory *_memory)
    : SimpleTimingPort(_name), memory(_memory)
{ }

void
PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
{
    memory->recvStatusChange(status);
}

void
PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
                                            AddrRangeList &snoop)
{
    memory->getAddressRanges(resp, snoop);
}

void
PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{
    snoop.clear();
    resp.clear();
    resp.push_back(RangeSize(params()->addrRange.start,
                             params()->addrRange.size()));
}

int
PhysicalMemory::MemoryPort::deviceBlockSize()
{
    return memory->deviceBlockSize();
}

Tick
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
{
    memory->doFunctionalAccess(pkt);
    return memory->calculateLatency(pkt);
}

void
PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
{
    //Since we are overriding the function, make sure to have the impl of the
    //check or functional accesses here.
    std::list<std::pair<Tick,PacketPtr> >::iterator i = transmitList.begin();
    std::list<std::pair<Tick,PacketPtr> >::iterator end = transmitList.end();
    bool notDone = true;

    while (i != end && notDone) {
        PacketPtr target = i->second;
        // If the target contains data, and it overlaps the
        // probed request, need to update data
        if (target->intersect(pkt))
            notDone = fixPacket(pkt, target);
        i++;
    }

    // Default implementation of SimpleTimingPort::recvFunctional()
    // calls recvAtomic() and throws away the latency; we can save a
    // little here by just not calculating the latency.
    memory->doFunctionalAccess(pkt);
}

unsigned int
PhysicalMemory::drain(Event *de)
{
    int count = port->drain(de);
    if (count)
        changeState(Draining);
    else
        changeState(Drained);
    return count;
}

void
PhysicalMemory::serialize(ostream &os)
{
    gzFile compressedMem;
    string filename = name() + ".physmem";

    SERIALIZE_SCALAR(filename);

    // write memory file
    string thefile = Checkpoint::dir() + "/" + filename.c_str();
    int fd = creat(thefile.c_str(), 0664);
    if (fd < 0) {
        perror("creat");
        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
    }

    compressedMem = gzdopen(fd, "wb");
    if (compressedMem == NULL)
        fatal("Insufficient memory to allocate compression state for %s\n",
                filename);

    if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
        fatal("Write failed on physical memory checkpoint file '%s'\n",
              filename);
    }

    if (gzclose(compressedMem))
        fatal("Close failed on physical memory checkpoint file '%s'\n",
              filename);
}

void
PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
{
    gzFile compressedMem;
    long *tempPage;
    long *pmem_current;
    uint64_t curSize;
    uint32_t bytesRead;
    const int chunkSize = 16384;

    string filename;

    UNSERIALIZE_SCALAR(filename);

    filename = cp->cptDir + "/" + filename;

    // mmap memoryfile
    int fd = open(filename.c_str(), O_RDONLY);
    if (fd < 0) {
        perror("open");
        fatal("Can't open physical memory checkpoint file '%s'", filename);
    }

    compressedMem = gzdopen(fd, "rb");
    if (compressedMem == NULL)
        fatal("Insufficient memory to allocate compression state for %s\n",
                filename);

    // unmap file that was mmaped in the constructor
    // This is done here to make sure that gzip and open don't muck with our
    // nice large space of memory before we reallocate it
    munmap(pmemAddr, params()->addrRange.size());

    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                MAP_ANON | MAP_PRIVATE, -1, 0);

    if (pmemAddr == (void *)MAP_FAILED) {
        perror("mmap");
        fatal("Could not mmap physical memory!\n");
    }

    curSize = 0;
    tempPage = (long*)malloc(chunkSize);
    if (tempPage == NULL)
        fatal("Unable to malloc memory to read file %s\n", filename);

    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
    while (curSize < params()->addrRange.size()) {
        bytesRead = gzread(compressedMem, tempPage, chunkSize);
        if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
            fatal("Read failed on physical memory checkpoint file '%s'"
                  " got %d bytes, expected %d or %d bytes\n",
                  filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);

        assert(bytesRead % sizeof(long) == 0);

        for (int x = 0; x < bytesRead/sizeof(long); x++)
        {
             if (*(tempPage+x) != 0) {
                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
                 *pmem_current = *(tempPage+x);
             }
        }
        curSize += bytesRead;
    }

    free(tempPage);

    if (gzclose(compressedMem))
        fatal("Close failed on physical memory checkpoint file '%s'\n",
              filename);

}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)

    Param<string> file;
    Param<Range<Addr> > range;
    Param<Tick> latency;
    Param<bool> zero;

END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)

BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)

    INIT_PARAM_DFLT(file, "memory mapped file", ""),
    INIT_PARAM(range, "Device Address Range"),
    INIT_PARAM(latency, "Memory access latency"),
    INIT_PARAM(zero, "Zero initialize memory")

END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)

CREATE_SIM_OBJECT(PhysicalMemory)
{
    PhysicalMemory::Params *p = new PhysicalMemory::Params;
    p->name = getInstanceName();
    p->addrRange = range;
    p->latency = latency;
    p->zero = zero;
    return new PhysicalMemory(p);
}

REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
<commit_msg>Change MemoryAccess dprintfs to print the data as well<commit_after>/*
 * Copyright (c) 2001-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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 COPYRIGHT
 * OWNER 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.
 *
 * Authors: Ron Dreslinski
 *          Ali Saidi
 */

#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <zlib.h>

#include <iostream>
#include <string>

#include "arch/isa_traits.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
#include "sim/builder.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"

using namespace std;
using namespace TheISA;

PhysicalMemory::PhysicalMemory(Params *p)
    : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
{
    if (params()->addrRange.size() % TheISA::PageBytes != 0)
        panic("Memory Size not divisible by page size\n");

    int map_flags = MAP_ANON | MAP_PRIVATE;
    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                map_flags, -1, 0);

    if (pmemAddr == (void *)MAP_FAILED) {
        perror("mmap");
        fatal("Could not mmap!\n");
    }

    //If requested, initialize all the memory to 0
    if(params()->zero)
        memset(pmemAddr, 0, params()->addrRange.size());

    pagePtr = 0;
}

void
PhysicalMemory::init()
{
    if (!port)
        panic("PhysicalMemory not connected to anything!");
    port->sendStatusChange(Port::RangeChange);
}

PhysicalMemory::~PhysicalMemory()
{
    if (pmemAddr)
        munmap(pmemAddr, params()->addrRange.size());
    //Remove memPorts?
}

Addr
PhysicalMemory::new_page()
{
    Addr return_addr = pagePtr << LogVMPageSize;
    return_addr += params()->addrRange.start;

    ++pagePtr;
    return return_addr;
}

int
PhysicalMemory::deviceBlockSize()
{
    //Can accept anysize request
    return 0;
}

Tick
PhysicalMemory::calculateLatency(PacketPtr pkt)
{
    return lat;
}

// Add load-locked to tracking list.  Should only be called if the
// operation is a load and the LOCKED flag is set.
void
PhysicalMemory::trackLoadLocked(Request *req)
{
    Addr paddr = LockedAddr::mask(req->getPaddr());

    // first we check if we already have a locked addr for this
    // xc.  Since each xc only gets one, we just update the
    // existing record with the new address.
    list<LockedAddr>::iterator i;

    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
        if (i->matchesContext(req)) {
            DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
                    req->getCpuNum(), req->getThreadNum(), paddr);
            i->addr = paddr;
            return;
        }
    }

    // no record for this xc: need to allocate a new one
    DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
            req->getCpuNum(), req->getThreadNum(), paddr);
    lockedAddrList.push_front(LockedAddr(req));
}

// Called on *writes* only... both regular stores and
// store-conditional operations.  Check for conventional stores which
// conflict with locked addresses, and for success/failure of store
// conditionals.
bool
PhysicalMemory::checkLockedAddrList(Request *req)
{
    Addr paddr = LockedAddr::mask(req->getPaddr());
    bool isLocked = req->isLocked();

    // Initialize return value.  Non-conditional stores always
    // succeed.  Assume conditional stores will fail until proven
    // otherwise.
    bool success = !isLocked;

    // Iterate over list.  Note that there could be multiple matching
    // records, as more than one context could have done a load locked
    // to this location.
    list<LockedAddr>::iterator i = lockedAddrList.begin();

    while (i != lockedAddrList.end()) {

        if (i->addr == paddr) {
            // we have a matching address

            if (isLocked && i->matchesContext(req)) {
                // it's a store conditional, and as far as the memory
                // system can tell, the requesting context's lock is
                // still valid.
                DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
                        req->getCpuNum(), req->getThreadNum(), paddr);
                success = true;
            }

            // Get rid of our record of this lock and advance to next
            DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
                    i->cpuNum, i->threadNum, paddr);
            i = lockedAddrList.erase(i);
        }
        else {
            // no match: advance to next record
            ++i;
        }
    }

    if (isLocked) {
        req->setScResult(success ? 1 : 0);
    }

    return success;
}

void
PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
{
    assert(pkt->getAddr() >= params()->addrRange.start &&
           pkt->getAddr() + pkt->getSize() <= params()->addrRange.start +
           params()->addrRange.size());

    if (pkt->isRead()) {
        if (pkt->req->isLocked()) {
            trackLoadLocked(pkt->req);
        }
        memcpy(pkt->getPtr<uint8_t>(),
               pmemAddr + pkt->getAddr() - params()->addrRange.start,
               pkt->getSize());
#if TRACING_ON
        switch (pkt->getSize()) {
          case sizeof(uint64_t):
            DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
                    pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
            break;
          case sizeof(uint32_t):
            DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
                    pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
            break;
          case sizeof(uint16_t):
            DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
                    pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
            break;
          case sizeof(uint8_t):
            DPRINTF(MemoryAccess, "Read of size %i on address 0x%x data 0x%x\n",
                    pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
            break;
          default:
            DPRINTF(MemoryAccess, "Read of size %i on address 0x%x\n",
                    pkt->getSize(), pkt->getAddr());
        }
#endif
    }
    else if (pkt->isWrite()) {
        if (writeOK(pkt->req)) {
            memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
                   pkt->getPtr<uint8_t>(), pkt->getSize());
#if TRACING_ON
            switch (pkt->getSize()) {
              case sizeof(uint64_t):
                DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
                        pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
                break;
              case sizeof(uint32_t):
                DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
                        pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
                break;
              case sizeof(uint16_t):
                DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
                        pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
                break;
              case sizeof(uint8_t):
                DPRINTF(MemoryAccess, "Write of size %i on address 0x%x data 0x%x\n",
                        pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
                break;
              default:
                DPRINTF(MemoryAccess, "Write of size %i on address 0x%x\n",
                        pkt->getSize(), pkt->getAddr());
            }
#endif
        }
    }
    else if (pkt->isInvalidate()) {
        //upgrade or invalidate
        pkt->flags |= SATISFIED;
    }
    else {
        panic("unimplemented");
    }

    pkt->result = Packet::Success;
}

Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
{
    if (if_name == "port" && idx == -1) {
        if (port != NULL)
           panic("PhysicalMemory::getPort: additional port requested to memory!");
        port = new MemoryPort(name() + "-port", this);
        return port;
    } else if (if_name == "functional") {
        /* special port for functional writes at startup. And for memtester */
        return new MemoryPort(name() + "-funcport", this);
    } else {
        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
    }
}

void
PhysicalMemory::recvStatusChange(Port::Status status)
{
}

PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
                                       PhysicalMemory *_memory)
    : SimpleTimingPort(_name), memory(_memory)
{ }

void
PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
{
    memory->recvStatusChange(status);
}

void
PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
                                            AddrRangeList &snoop)
{
    memory->getAddressRanges(resp, snoop);
}

void
PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{
    snoop.clear();
    resp.clear();
    resp.push_back(RangeSize(params()->addrRange.start,
                             params()->addrRange.size()));
}

int
PhysicalMemory::MemoryPort::deviceBlockSize()
{
    return memory->deviceBlockSize();
}

Tick
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
{
    memory->doFunctionalAccess(pkt);
    return memory->calculateLatency(pkt);
}

void
PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
{
    //Since we are overriding the function, make sure to have the impl of the
    //check or functional accesses here.
    std::list<std::pair<Tick,PacketPtr> >::iterator i = transmitList.begin();
    std::list<std::pair<Tick,PacketPtr> >::iterator end = transmitList.end();
    bool notDone = true;

    while (i != end && notDone) {
        PacketPtr target = i->second;
        // If the target contains data, and it overlaps the
        // probed request, need to update data
        if (target->intersect(pkt))
            notDone = fixPacket(pkt, target);
        i++;
    }

    // Default implementation of SimpleTimingPort::recvFunctional()
    // calls recvAtomic() and throws away the latency; we can save a
    // little here by just not calculating the latency.
    memory->doFunctionalAccess(pkt);
}

unsigned int
PhysicalMemory::drain(Event *de)
{
    int count = port->drain(de);
    if (count)
        changeState(Draining);
    else
        changeState(Drained);
    return count;
}

void
PhysicalMemory::serialize(ostream &os)
{
    gzFile compressedMem;
    string filename = name() + ".physmem";

    SERIALIZE_SCALAR(filename);

    // write memory file
    string thefile = Checkpoint::dir() + "/" + filename.c_str();
    int fd = creat(thefile.c_str(), 0664);
    if (fd < 0) {
        perror("creat");
        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
    }

    compressedMem = gzdopen(fd, "wb");
    if (compressedMem == NULL)
        fatal("Insufficient memory to allocate compression state for %s\n",
                filename);

    if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
        fatal("Write failed on physical memory checkpoint file '%s'\n",
              filename);
    }

    if (gzclose(compressedMem))
        fatal("Close failed on physical memory checkpoint file '%s'\n",
              filename);
}

void
PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
{
    gzFile compressedMem;
    long *tempPage;
    long *pmem_current;
    uint64_t curSize;
    uint32_t bytesRead;
    const int chunkSize = 16384;

    string filename;

    UNSERIALIZE_SCALAR(filename);

    filename = cp->cptDir + "/" + filename;

    // mmap memoryfile
    int fd = open(filename.c_str(), O_RDONLY);
    if (fd < 0) {
        perror("open");
        fatal("Can't open physical memory checkpoint file '%s'", filename);
    }

    compressedMem = gzdopen(fd, "rb");
    if (compressedMem == NULL)
        fatal("Insufficient memory to allocate compression state for %s\n",
                filename);

    // unmap file that was mmaped in the constructor
    // This is done here to make sure that gzip and open don't muck with our
    // nice large space of memory before we reallocate it
    munmap(pmemAddr, params()->addrRange.size());

    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                MAP_ANON | MAP_PRIVATE, -1, 0);

    if (pmemAddr == (void *)MAP_FAILED) {
        perror("mmap");
        fatal("Could not mmap physical memory!\n");
    }

    curSize = 0;
    tempPage = (long*)malloc(chunkSize);
    if (tempPage == NULL)
        fatal("Unable to malloc memory to read file %s\n", filename);

    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
    while (curSize < params()->addrRange.size()) {
        bytesRead = gzread(compressedMem, tempPage, chunkSize);
        if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
            fatal("Read failed on physical memory checkpoint file '%s'"
                  " got %d bytes, expected %d or %d bytes\n",
                  filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);

        assert(bytesRead % sizeof(long) == 0);

        for (int x = 0; x < bytesRead/sizeof(long); x++)
        {
             if (*(tempPage+x) != 0) {
                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
                 *pmem_current = *(tempPage+x);
             }
        }
        curSize += bytesRead;
    }

    free(tempPage);

    if (gzclose(compressedMem))
        fatal("Close failed on physical memory checkpoint file '%s'\n",
              filename);

}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)

    Param<string> file;
    Param<Range<Addr> > range;
    Param<Tick> latency;
    Param<bool> zero;

END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)

BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)

    INIT_PARAM_DFLT(file, "memory mapped file", ""),
    INIT_PARAM(range, "Device Address Range"),
    INIT_PARAM(latency, "Memory access latency"),
    INIT_PARAM(zero, "Zero initialize memory")

END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)

CREATE_SIM_OBJECT(PhysicalMemory)
{
    PhysicalMemory::Params *p = new PhysicalMemory::Params;
    p->name = getInstanceName();
    p->addrRange = range;
    p->latency = latency;
    p->zero = zero;
    return new PhysicalMemory(p);
}

REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
<|endoftext|>


<commit_before>#include <QMessageBox>
#include <QMimeData>
#include <QUrl>

#include "ipobjects.h"
#include "membermodel.h"
#include "filehandler.h"

MemberModel::MemberModel(QObject *parent=0) : QStandardItemModel(parent) {
}

MemberFilter::MemberFilter(QObject *parent=0) : QSortFilterProxyModel(parent) {}

Qt::ItemFlags MemberModel::flags(const QModelIndex& index) const
{
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled ;
}

bool MemberModel::okToInsert( Member* item )
{
    if(MemberUtils::contains("members_list", item))
        return false;

    MemberUtils::insert("members_list", item);
    return true;
}

void MemberModel::insertRow( int row, QStandardItem* item )
{
    if(okToInsert((Member*)item))
        QStandardItemModel::insertRow(row, item);
}

void MemberModel::appendRow( QStandardItem * item)
{
    if(okToInsert((Member*)item))
        QStandardItemModel::appendRow(item);
}

void MemberModel::setGroupCount(QStandardItem* group)
{
    group->setData(tr("Members: %1").arg(group->rowCount()), Qt::ToolTipRole);
}

void MemberModel::updateGroupCount(QStandardItem *item)
{
    if(item->parent())
    {
        setGroupCount(item->parent());
    }
}

bool MemberModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
    QStringList files;
    foreach(QUrl url, data->urls())
    {
        files << url.toLocalFile();
    }

    fileHandler()->sendFilesRequest(files, (Member*)itemFromIndex(parent.child(row, column)), "");
}

bool MemberFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
    if( sourceParent.isValid() && sourceModel()->data(sourceParent).toString().contains(filterRegExp()) ) return true;

    QString data = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString();

    bool ret = data.contains(filterRegExp());

    QModelIndex subIndex = sourceModel()->index(sourceRow, 0, sourceParent);
    if( subIndex.isValid() )
    {
        for(int i = 0; i < sourceModel()->rowCount(subIndex); ++i)
        {
            ret = ret || filterAcceptsRow(i, subIndex);
        }
    }
    return ret;
}
<commit_msg>okToInsert is only called if the item is a Member<commit_after>#include <QMessageBox>
#include <QMimeData>
#include <QUrl>

#include "ipobjects.h"
#include "membermodel.h"
#include "filehandler.h"

MemberModel::MemberModel(QObject *parent=0) : QStandardItemModel(parent) {
}

MemberFilter::MemberFilter(QObject *parent=0) : QSortFilterProxyModel(parent) {}

Qt::ItemFlags MemberModel::flags(const QModelIndex& index) const
{
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled ;
}

bool MemberModel::okToInsert( Member* item )
{
    if(MemberUtils::contains("members_list", item))
        return false;

    MemberUtils::insert("members_list", item);
    return true;
}

void MemberModel::insertRow( int row, QStandardItem* item )
{
    if(item->type() == TYPE_MEMBER && !okToInsert((Member*)item))
        return;
    QStandardItemModel::insertRow(row, item);
}

void MemberModel::appendRow( QStandardItem * item)
{
    if(item->type() == TYPE_MEMBER && !okToInsert((Member*)item))
        return;
    QStandardItemModel::appendRow(item);
}

void MemberModel::setGroupCount(QStandardItem* group)
{
    group->setData(tr("Members: %1").arg(group->rowCount()), Qt::ToolTipRole);
}

void MemberModel::updateGroupCount(QStandardItem *item)
{
    if(item->parent())
    {
        setGroupCount(item->parent());
    }
}

bool MemberModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
    QStringList files;
    foreach(QUrl url, data->urls())
    {
        files << url.toLocalFile();
    }

    fileHandler()->sendFilesRequest(files, (Member*)itemFromIndex(parent.child(row, column)), "");
}

bool MemberFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
    if( sourceParent.isValid() && sourceModel()->data(sourceParent).toString().contains(filterRegExp()) ) return true;

    QString data = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString();

    bool ret = data.contains(filterRegExp());

    QModelIndex subIndex = sourceModel()->index(sourceRow, 0, sourceParent);
    if( subIndex.isValid() )
    {
        for(int i = 0; i < sourceModel()->rowCount(subIndex); ++i)
        {
            ret = ret || filterAcceptsRow(i, subIndex);
        }
    }
    return ret;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "memory_stats.h"

#include "log.h"                 // for L_ERR

#include <sys/param.h>           // for statfs, sysctl
#include <sys/mount.h>           // for statfs, sysctl
#include <sys/sysctl.h>          // for xsw_usage, sysctlnametomib, sysctl

#if defined(__APPLE__)
#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/mach.h>           // for task_basic_info
#elif defined(__FreeBSD__)
#include <fcntl.h>
#include <kvm.h>
#include <sys/stat.h>
#include <unistd.h>              // for getpagesize
#endif

std::pair<int64_t, int64_t> get_current_ram()
{
#ifdef __APPLE__
	/* Total ram current in use */
	vm_size_t page_size;
	mach_port_t mach_port;
	mach_msg_type_number_t count;
	vm_statistics64_data_t vm_stats;

	mach_port = mach_host_self();
	count = sizeof(vm_stats) / sizeof(natural_t);
	if (KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
		KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count)) {
		int64_t free_memory = (int64_t)vm_stats.free_count * (int64_t)page_size;
		int64_t used_memory = ((int64_t)vm_stats.active_count +
								 (int64_t)vm_stats.inactive_count +
								 (int64_t)vm_stats.wire_count) *  (int64_t)page_size;
		return std::make_pair(used_memory, free_memory);
	}
#endif
	return std::make_pair(0, 0);
}

uint64_t get_total_virtual_used()
{
	uint64_t total_virtual_used = 0;

#if defined(VM_SWAPUSAGE)
#define _SYSCTL_NAME "vm.swapusage"  // Apple
	int mib[] = {CTL_VM, VM_SWAPUSAGE};
	size_t mib_len = sizeof(mib) / sizeof(int);
#endif
#ifdef _SYSCTL_NAME
	xsw_usage vmusage = {0, 0, 0, 0, false};
	size_t vmusage_len = sizeof(vmusage);
	if (sysctl(mib, mib_len, &vmusage, &vmusage_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get swap usage: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	} else {
		total_virtual_used = vmusage.xsu_used;
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting swap usage.");
#endif

	return total_virtual_used;
}

uint64_t get_total_ram()
{
	uint64_t total_ram = 0;

#if defined(HW_REALMEM)
#define _SYSCTL_NAME "hw.realmem"  // FreeBSD
	int mib[] = {CTL_HW, HW_REALMEM};
	size_t mib_len = sizeof(mib) / sizeof(int);
#elif defined(HW_MEMSIZE)
#define _SYSCTL_NAME "hw.memsize"  // Apple
	int mib[] = {CTL_HW, HW_MEMSIZE};
	size_t mib_len = sizeof(mib) / sizeof(int);
#endif
#ifdef _SYSCTL_NAME
	auto total_ram_len = sizeof(total_ram);
	if (sysctl(mib, mib_len, &total_ram, &total_ram_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get total memory size: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting total memory size.");
#endif

	return total_ram;
}

uint64_t get_current_memory_by_process(bool resident)
{
	uint64_t current_memory_by_process;
#if defined(__FreeBSD__)
	char errbuf[100];
	struct kinfo_proc *p;
	int cnt;

	kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, O_RDWR, errbuf);
	p = kvm_getprocs(kd, KERN_PROC_PID | KERN_PROC_INC_THREAD, getpid(), &cnt);
	current_memory_by_process = p->ki_rssize * getpagesize();
#elif defined(__APPLE__)
	struct task_basic_info t_info;
	mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

	if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) {
		return 0;
	}
	if (resident) {
		current_memory_by_process = t_info.resident_size;
	} else {
		current_memory_by_process = t_info.virtual_size;
	}
#endif
	return current_memory_by_process;
}

uint64_t get_total_virtual_memory()
{
	uint64_t total_virtual_memory = 0;

#if defined(__APPLE__)
	struct statfs stats;
	if (0 == statfs("/", &stats)) {
		total_virtual_memory = (uint64_t)stats.f_bsize * stats.f_bfree;
	}
#elif defined(__FreeBSD__)
#define _SYSCTL_NAME "vm.stats.vm.v_page_count"  // FreeBSD
	int mib[CTL_MAXNAME + 2];
	size_t mib_len = sizeof(mib) / sizeof(int);
	if (sysctlnametomib(_SYSCTL_NAME, mib, &mib_len) < 0) {
		L_ERR(nullptr, "ERROR: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
		return 0;
	}
#endif
#ifdef _SYSCTL_NAME
	int64_t total_pages;
	auto total_pages_len = sizeof(total_pages);
	if (sysctl(mib, mib_len, &total_pages, &total_pages_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get total virtual memory size: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	} else {
		total_virtual_memory = total_pages * getpagesize();
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting total virtual memory size.");
#endif

	return total_virtual_memory;
}
<commit_msg>Formatting<commit_after>/*
 * Copyright (C) 2017 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "memory_stats.h"

#include "log.h"                 // for L_ERR

#include <sys/param.h>           // for statfs, sysctl
#include <sys/mount.h>           // for statfs, sysctl
#include <sys/sysctl.h>          // for xsw_usage, sysctlnametomib, sysctl

#if defined(__APPLE__)
#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/mach.h>           // for task_basic_info
#elif defined(__FreeBSD__)
#include <fcntl.h>
#include <kvm.h>
#include <sys/stat.h>
#include <unistd.h>              // for getpagesize
#endif

std::pair<int64_t, int64_t> get_current_ram()
{
#ifdef __APPLE__
	/* Total ram current in use */
	vm_size_t page_size;
	mach_port_t mach_port;
	mach_msg_type_number_t count;
	vm_statistics64_data_t vm_stats;

	mach_port = mach_host_self();
	count = sizeof(vm_stats) / sizeof(natural_t);
	if (KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
		KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count)) {
		int64_t free_memory = ((int64_t)vm_stats.free_count * (int64_t)page_size);
		int64_t used_memory = ((int64_t)vm_stats.active_count +
							   (int64_t)vm_stats.inactive_count +
							   (int64_t)vm_stats.wire_count) * (int64_t)page_size;
		return std::make_pair(used_memory, free_memory);
	}
#endif
	return std::make_pair(0, 0);
}

uint64_t get_total_virtual_used()
{
	uint64_t total_virtual_used = 0;

#if defined(VM_SWAPUSAGE)
#define _SYSCTL_NAME "vm.swapusage"  // Apple
	int mib[] = {CTL_VM, VM_SWAPUSAGE};
	size_t mib_len = sizeof(mib) / sizeof(int);
#endif
#ifdef _SYSCTL_NAME
	xsw_usage vmusage = {0, 0, 0, 0, false};
	size_t vmusage_len = sizeof(vmusage);
	if (sysctl(mib, mib_len, &vmusage, &vmusage_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get swap usage: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	} else {
		total_virtual_used = vmusage.xsu_used;
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting swap usage.");
#endif

	return total_virtual_used;
}

uint64_t get_total_ram()
{
	uint64_t total_ram = 0;

#if defined(HW_REALMEM)
#define _SYSCTL_NAME "hw.realmem"  // FreeBSD
	int mib[] = {CTL_HW, HW_REALMEM};
	size_t mib_len = sizeof(mib) / sizeof(int);
#elif defined(HW_MEMSIZE)
#define _SYSCTL_NAME "hw.memsize"  // Apple
	int mib[] = {CTL_HW, HW_MEMSIZE};
	size_t mib_len = sizeof(mib) / sizeof(int);
#endif
#ifdef _SYSCTL_NAME
	auto total_ram_len = sizeof(total_ram);
	if (sysctl(mib, mib_len, &total_ram, &total_ram_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get total memory size: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting total memory size.");
#endif

	return total_ram;
}

uint64_t get_current_memory_by_process(bool resident)
{
	uint64_t current_memory_by_process;
#if defined(__FreeBSD__)
	char errbuf[100];
	struct kinfo_proc *p;
	int cnt;

	kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, O_RDWR, errbuf);
	p = kvm_getprocs(kd, KERN_PROC_PID | KERN_PROC_INC_THREAD, getpid(), &cnt);
	current_memory_by_process = p->ki_rssize * getpagesize();
#elif defined(__APPLE__)
	struct task_basic_info t_info;
	mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

	if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) {
		return 0;
	}
	if (resident) {
		current_memory_by_process = t_info.resident_size;
	} else {
		current_memory_by_process = t_info.virtual_size;
	}
#endif
	return current_memory_by_process;
}

uint64_t get_total_virtual_memory()
{
	uint64_t total_virtual_memory = 0;

#if defined(__APPLE__)
	struct statfs stats;
	if (0 == statfs("/", &stats)) {
		total_virtual_memory = (uint64_t)stats.f_bsize * stats.f_bfree;
	}
#elif defined(__FreeBSD__)
#define _SYSCTL_NAME "vm.stats.vm.v_page_count"  // FreeBSD
	int mib[CTL_MAXNAME + 2];
	size_t mib_len = sizeof(mib) / sizeof(int);
	if (sysctlnametomib(_SYSCTL_NAME, mib, &mib_len) < 0) {
		L_ERR(nullptr, "ERROR: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
		return 0;
	}
#endif
#ifdef _SYSCTL_NAME
	int64_t total_pages;
	auto total_pages_len = sizeof(total_pages);
	if (sysctl(mib, mib_len, &total_pages, &total_pages_len, nullptr, 0) < 0) {
		L_ERR(nullptr, "ERROR: Unable to get total virtual memory size: sysctl(" _SYSCTL_NAME "): [%d] %s", errno, strerror(errno));
	} else {
		total_virtual_memory = total_pages * getpagesize();
	}
#undef _SYSCTL_NAME
#else
	L_WARNING(nullptr, "WARNING: No way of getting total virtual memory size.");
#endif

	return total_virtual_memory;
}
<|endoftext|>