<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/signcommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "signcommand.h"
#include "kleo-assuan.h"
#include "keyselectionjob.h"

#include "utils/stl_util.h"

#include <kleo/keylistjob.h>
#include <kleo/signjob.h>
#include <kleo/cryptobackendfactory.h>

#include <gpgme++/data.h>
#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <gpgme++/signingresult.h>

#include <KLocale>

#include <QIODevice>
#include <QString>
#include <QStringList>
#include <QObject>
#include <QDebug>

#include <boost/bind.hpp>

using namespace Kleo;

namespace {
    template <template <typename T> class Op>
    struct ByProtocol {
        typedef bool result_type;

        bool operator()( const GpgME::Key & lhs, const GpgME::Key & rhs ) const {
            return Op<int>()( qstricmp( lhs.protocolAsString(), rhs.protocolAsString() ), 0 );
        }
        bool operator()( const GpgME::Key & lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs.protocolAsString(), rhs ), 0 );
        }
        bool operator()( const char * lhs, const GpgME::Key & rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs.protocolAsString() ), 0 );
        }
        bool operator()( const char * lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs ), 0 );
        }
    };

}

class SignCommand::Private
  : public AssuanCommandPrivateBaseMixin<SignCommand::Private, SignCommand>
{
    Q_OBJECT
public:
    Private( SignCommand * qq )
        :AssuanCommandPrivateBaseMixin<SignCommand::Private, SignCommand>()
        , q( qq ), m_signJobs( 0 ), m_statusSent( 0 )
    {}
    virtual ~Private() {}

    void checkInputs();
    void startKeySelection();
    void startSignJobs( const std::vector<GpgME::Key>& keys );
    void showKeySelectionDialog();

    struct Input {
        QIODevice* data;
        QString dataFileName;
        unsigned int id;
    };

    struct Result {
        GpgME::SigningResult result;
        QByteArray data;
        unsigned int id;
        unsigned int error;
        QString errorString;
    };

    SignCommand *q;

private Q_SLOTS:
    void slotKeySelectionResult( const std::vector<GpgME::Key>& );
    void slotKeySelectionError( const GpgME::Error& error, const GpgME::KeyListResult& );
    void slotSigningResult( const GpgME::SigningResult & result, const QByteArray & signature );
private:
    bool trySendingStatus( const QString & str );

    std::vector<Input> m_inputs;
    QMap<int, Result> m_results;
    QMap<const SignJob*, unsigned int> m_jobs;
    int m_signJobs;
    int m_statusSent;
};

void SignCommand::Private::checkInputs()
{
    const int numInputs = q->numBulkInputDevices( "INPUT" );
    const int numOutputs = q->numBulkOutputDevices( "OUTPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    //TODO use better error code if possible
    if ( numMessages != 0 )
        throw assuan_exception(makeError( GPG_ERR_ASS_NO_INPUT ), i18n( "Only --input and --output can be provided to the sign command, no --message") );

    // either the output is discarded, or there ar as many as inputs
    //TODO use better error code if possible
    if ( numOutputs > 0 && numInputs != numOutputs )
        throw assuan_exception( makeError( GPG_ERR_ASS_NO_INPUT ),  i18n( "For each --input there needs to be an --output") );

    for ( int i = 0; i < numInputs; ++i ) {
        Input input;
        input.id = i;
        input.data = q->bulkInputDevice( "INPUT", i );
        input.dataFileName = q->bulkInputDeviceFileName( "INPUT", i );

        m_inputs.push_back( input );
    }
}

void SignCommand::Private::startKeySelection()
{
    KeySelectionJob* job = new KeySelectionJob( this );
    job->setSecretKeysOnly( true );
    job->setPatterns( QStringList() ); // FIXME
    connect( job, SIGNAL( error( GpgME::Error, GpgME::KeyListResult ) ),
             this, SLOT( slotKeySelectionError( GpgME::Error, GpgME::KeyListResult ) ) );
    connect( job, SIGNAL( result( std::vector<GpgME::Key> ) ),
             this, SLOT( slotKeySelectionResult( std::vector<GpgME::Key> ) ) );
    job->start();
}

void SignCommand::Private::startSignJobs( const std::vector<GpgME::Key>& keys )
{
    // make sure the keys are all of the same type
    // FIXME reasonable assumption?
    if ( keys.empty() || !kdtools::all( keys.begin(), keys.end(), boost::bind( ByProtocol<std::equal_to>(), _1, keys.front() )  ) ) {
        q->done();
        return;
    }
    const CryptoBackend::Protocol* backend = CryptoBackendFactory::instance()->protocol( keys.front().protocolAsString() );

    assert( backend );

    Q_FOREACH( const Input input, m_inputs ) {
        SignJob *job = backend->signJob();
        connect( job, SIGNAL( result( GpgME::SigningResult, QByteArray ) ),
                 this, SLOT( slotSigningResult( GpgME::SigningResult, QByteArray ) ) );
        // FIXME port to iodevice
        // FIXME mode?
        if ( const GpgME::Error err = job->start( keys, input.data->readAll(), GpgME::NormalSignatureMode ) ) {
            q->done( err );
            return;
        }
        m_jobs.insert( job, input.id );
        m_signJobs++;
    }
}

void SignCommand::Private::slotKeySelectionResult( const std::vector<GpgME::Key>& keys )
{
    // fire off the sign jobs
    startSignJobs( keys );
}

void SignCommand::Private::slotKeySelectionError( const GpgME::Error& error, const GpgME::KeyListResult& )
{
    assert( error );
    if ( error == q->makeError( GPG_ERR_CANCELED ) )
        q->done( error, i18n( "User canceled key selection" ) );
    else
        q->done( error, i18n( "Error while listing and selecting private keys" ) );

}

bool SignCommand::Private::trySendingStatus( const QString & str )
{
    if ( const int err = q->sendStatus( "SIGN", str ) ) {
        QString errorString = i18n("Problem writing out the signature.");
        q->done( err, errorString );
        return false;
    }
    return true;
}

void SignCommand::Private::slotSigningResult( const GpgME::SigningResult & result, const QByteArray & signature )
{
    const SignJob * const job = qobject_cast<SignJob*>( sender() );
    assert( job );
    assert( m_jobs.contains( job ) );
    const unsigned int id = m_jobs[job];

    {
        Result res;
        res.result = result;
        res.data = signature;
        res.id = id;
        m_results.insert( id, res );
    }
    // send status for all results received so far, but in order of id
    while ( m_results.contains( m_statusSent ) ) {
       SignCommand::Private::Result result = m_results[m_statusSent];
       QString resultString;
       try {
           const GpgME::SigningResult & signres = result.result;
           assert( !signres.isNull() );

           const GpgME::Error signError = signres.error();
           if ( signError )
               throw assuan_exception( signError, i18n( "Signing failed: " ) );
           // FIXME adjust for smime?
           const QString filename = q->bulkInputDeviceFileName( "INPUT", m_statusSent ) + ".sig";
           writeToOutputDeviceOrAskForFileName( result.id, result.data, filename );
           resultString = "OK - Signature written";
       } catch ( const assuan_exception& e ) {
           result.error = e.error_code();
           result.errorString = e.what();
           m_results[result.id] = result;
           resultString = "ERR " + result.errorString;
           // FIXME ask to continue or cancel
       }
       if ( !trySendingStatus( resultString ) ) // emit done on error
           return;

       m_statusSent++;
    }

    if ( --m_signJobs == 0 )
        q->done();
}

SignCommand::SignCommand()
:d( new Private( this ) )
{
}

SignCommand::~SignCommand()
{
}

int SignCommand::doStart()
{
    try {
        d->checkInputs();
        d->startKeySelection();
    } catch ( const assuan_exception& e ) {
        done( e.error_code(), e.what());
        return e.error_code();
    }

    return 0;
}

void SignCommand::doCanceled()
{
}

#include "signcommand.moc"
<commit_msg>Fixup SIGN command.<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/signcommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "signcommand.h"
#include "kleo-assuan.h"
#include "keyselectionjob.h"

#include "utils/stl_util.h"

#include <kleo/keylistjob.h>
#include <kleo/signjob.h>
#include <kleo/cryptobackendfactory.h>

#include <gpgme++/data.h>
#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <gpgme++/signingresult.h>

#include <KLocale>

#include <QIODevice>
#include <QString>
#include <QStringList>
#include <QObject>
#include <QDebug>

#include <boost/bind.hpp>

using namespace Kleo;

namespace {
    template <template <typename T> class Op>
    struct ByProtocol {
        typedef bool result_type;

        bool operator()( const GpgME::Key & lhs, const GpgME::Key & rhs ) const {
            return Op<int>()( qstricmp( lhs.protocolAsString(), rhs.protocolAsString() ), 0 );
        }
        bool operator()( const GpgME::Key & lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs.protocolAsString(), rhs ), 0 );
        }
        bool operator()( const char * lhs, const GpgME::Key & rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs.protocolAsString() ), 0 );
        }
        bool operator()( const char * lhs, const char * rhs ) const {
            return Op<int>()( qstricmp( lhs, rhs ), 0 );
        }
    };

}

class SignCommand::Private
  : public AssuanCommandPrivateBaseMixin<SignCommand::Private, SignCommand>
{
    Q_OBJECT
public:
    Private( SignCommand * qq )
        :AssuanCommandPrivateBaseMixin<SignCommand::Private, SignCommand>()
        , q( qq ), m_signJobs( 0 ), m_statusSent( 0 )
    {}
    virtual ~Private() {}

    void checkInputs();
    void startKeySelection();
    void startSignJobs( const std::vector<GpgME::Key>& keys );
    void showKeySelectionDialog();

    struct Input {
        QIODevice* data;
        QString dataFileName;
        unsigned int id;
    };

    struct Result {
        GpgME::SigningResult result;
        QByteArray data;
        unsigned int id;
        unsigned int error;
        QString errorString;
    };

    SignCommand *q;

private Q_SLOTS:
    void slotKeySelectionResult( const std::vector<GpgME::Key>& );
    void slotKeySelectionError( const GpgME::Error& error, const GpgME::KeyListResult& );
    void slotSigningResult( const GpgME::SigningResult & result, const QByteArray & signature );
private:
    bool trySendingStatus( const QString & str );

    std::vector<Input> m_inputs;
    QMap<int, Result> m_results;
    QMap<const SignJob*, unsigned int> m_jobs;
    int m_signJobs;
    int m_statusSent;
};

void SignCommand::Private::checkInputs()
{
    const int numInputs = q->numBulkInputDevices( "INPUT" );
    const int numOutputs = q->numBulkOutputDevices( "OUTPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    //TODO use better error code if possible
    if ( numMessages != 0 )
        throw assuan_exception(makeError( GPG_ERR_ASS_NO_INPUT ), i18n( "Only INPUT and OUTPUT can be provided to the sign command, MESSAGE") );

    // either the output is discarded, or there ar as many as inputs
    //TODO use better error code if possible
    if ( numOutputs > 0 && numInputs != numOutputs )
        throw assuan_exception( makeError( GPG_ERR_ASS_NO_INPUT ),  i18n( "For each INPUT there needs to be an OUTPUT") );

    for ( int i = 0; i < numInputs; ++i ) {
        Input input;
        input.id = i;
        input.data = q->bulkInputDevice( "INPUT", i );
        input.dataFileName = q->bulkInputDeviceFileName( "INPUT", i );

        m_inputs.push_back( input );
    }
}

void SignCommand::Private::startKeySelection()
{
    KeySelectionJob* job = new KeySelectionJob( this );
    job->setSecretKeysOnly( true );
    job->setPatterns( q->senders() ); // FIXME
    job->setSilent( q->hasOption( "silent" ) );
    connect( job, SIGNAL( error( GpgME::Error, GpgME::KeyListResult ) ),
             this, SLOT( slotKeySelectionError( GpgME::Error, GpgME::KeyListResult ) ) );
    connect( job, SIGNAL( result( std::vector<GpgME::Key> ) ),
             this, SLOT( slotKeySelectionResult( std::vector<GpgME::Key> ) ) );
    job->start();
}

void SignCommand::Private::startSignJobs( const std::vector<GpgME::Key>& keys )
{
    // make sure the keys are all of the same type
    // FIXME reasonable assumption?
    if ( keys.empty() || !kdtools::all( keys.begin(), keys.end(), boost::bind( ByProtocol<std::equal_to>(), _1, keys.front() )  ) ) {
        q->done();
        return;
    }
    const CryptoBackend::Protocol* backend = CryptoBackendFactory::instance()->protocol( keys.front().protocolAsString() );

    assert( backend );

    Q_FOREACH( const Input input, m_inputs ) {
        SignJob *job = backend->signJob( true, true );
        connect( job, SIGNAL( result( GpgME::SigningResult, QByteArray ) ),
                 this, SLOT( slotSigningResult( GpgME::SigningResult, QByteArray ) ) );
        // FIXME port to iodevice
        if ( const GpgME::Error err = job->start( keys, input.data->readAll(), q->hasOption( "detached" ) ? GpgME::Detached : GpgME::NormalSignatureMode ) ) {
            q->done( err );
            return;
        }
        m_jobs.insert( job, input.id );
        m_signJobs++;
    }
}

void SignCommand::Private::slotKeySelectionResult( const std::vector<GpgME::Key>& keys )
{
    // fire off the sign jobs
    startSignJobs( keys );
}

void SignCommand::Private::slotKeySelectionError( const GpgME::Error& error, const GpgME::KeyListResult& )
{
    assert( error || error.isCanceled() );
    if ( error.isCanceled() )
        q->done( error, i18n( "User canceled key selection" ) );
    else
        q->done( error, i18n( "Error while listing and selecting private keys" ) );

}

bool SignCommand::Private::trySendingStatus( const QString & str )
{
    if ( const int err = q->sendStatus( "SIGN", str ) ) {
        QString errorString = i18n("Problem writing out the signature.");
        q->done( err, errorString );
        return false;
    }
    return true;
}

void SignCommand::Private::slotSigningResult( const GpgME::SigningResult & result, const QByteArray & signature )
{
    const SignJob * const job = qobject_cast<SignJob*>( sender() );
    assert( job );
    assert( m_jobs.contains( job ) );
    const unsigned int id = m_jobs[job];

    {
        Result res;
        res.result = result;
        res.data = signature;
        res.id = id;
        m_results.insert( id, res );
    }
    // send status for all results received so far, but in order of id
    while ( m_results.contains( m_statusSent ) ) {
       SignCommand::Private::Result result = m_results[m_statusSent];
       QString resultString;
       try {
           const GpgME::SigningResult & signres = result.result;
           assert( !signres.isNull() );

           const GpgME::Error signError = signres.error();
           if ( signError )
               throw assuan_exception( signError, i18n( "Signing failed: " ) );
           // FIXME adjust for smime?
           const QString filename = q->bulkInputDeviceFileName( "INPUT", m_statusSent ) + ".sig";
           writeToOutputDeviceOrAskForFileName( result.id, result.data, filename );
           resultString = "OK - Signature written";
       } catch ( const assuan_exception& e ) {
           result.error = e.error_code();
           result.errorString = e.what();
           m_results[result.id] = result;
           resultString = "ERR " + result.errorString;
           // FIXME ask to continue or cancel
       }
       if ( !trySendingStatus( resultString ) ) // emit done on error
           return;

       m_statusSent++;
    }

    if ( --m_signJobs == 0 )
        q->done();
}

SignCommand::SignCommand()
:d( new Private( this ) )
{
}

SignCommand::~SignCommand()
{
}

int SignCommand::doStart()
{
    try {
        d->checkInputs();
        d->startKeySelection();
    } catch ( const assuan_exception& e ) {
        done( e.error_code(), e.what());
        return e.error_code();
    }

    return 0;
}

void SignCommand::doCanceled()
{
}

#include "signcommand.moc"
<|endoftext|>


<commit_before>/* conduitConfigDialog.cc                KPilot
**
** Copyright (C) 2004 by Dan Pilone
** Written 2004 by Reinhold Kainhofer
**
** This file defines a .ui-based configuration dialog for conduits.
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
** MA 02111-1307, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include <qlayout.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qvbox.h>
#include <qtimer.h>
#include <qmap.h>
#include <qvaluelist.h>

#include <kmessagebox.h>
#include <kglobal.h>
#include <klocale.h>
#include <kconfigskeleton.h>
#include <kapplication.h>
#include <kprogress.h>

#include "kpilotConfig.h"
#include "pilotUser.h"
#include "pilotSysInfo.h"
#include "options.h"
#include "kpilotlink.h"

#include "kpilotProbeDialog.moc"
#ifndef __PILOTDAEMONDCOP_STUB__
#include "pilotDaemonDCOP_stub.h"
#endif

/*
We can't connect to /dev/ttyUSB0 and /dev/ttyUSB1 at the same time, because that will lock up kpilot completely. In particular, it gets a connection on /dev/ttyUSB0, which it processes, and while processing, a connection on USB1 is also detected. However, when kpilot gets 'round to process it, the link is already closed, and pi_connect hangs forever.

Now, I split up the list of devices to probe into three list, one holding /dev/pilot, the second holding all /dev/*0 and /dev/*2 (e.g. /dev/ttyUSB0 and /dev/ttyUSB2), and finally a third holding the remaining /dev/*1 and /dev/*3 devices. Each of these three sets of devices is activated for a few seconds, and then the next set is probed. This way, I ensure that kpilot never listens on /dev/ttyUSB0 and /dev/ttyUSB1 at the same time.

Now the first detection works fine. However, it seems the Linux kernel has another problem with /dev/ttyUSB0. I have a Clie, which uses ttyUSB0, and as soon as the wizard tries to listen on ttyUSB1 (after it detected the handheld on ttyUSB0 already), the kernel writes a warning message to the syslog:
visor ttyUSB1: Device lied about number of ports, please use a lower one.

If I continue autodetection once again afterwards, the visor module kind of crashes. lsmod shows an impossible usage count for the module:
reinhold@einstein:/kde/builddir$ lsmod
Module                  Size  Used by
visor                  17164  4294967294
usbserial              30704  1 visor

After that, the kernel doesn't detect the device ever again (until the computer is rebootet), and the module can't be unloaded.
*/

ProbeDialog::ProbeDialog(QWidget *parent, const char *n) :
	KDialogBase(parent, n, true, i18n("Autodetecting Your Handheld"), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Cancel, true, i18n("Restart detection...")),
	mDetected(false), mUserName(""), mDevice(""), mUID(0)
{
	QVBox *mainWidget = makeVBoxMainWidget();

	fInfoText = new QLabel( i18n( "KPilot is now trying to automatically detect the device of your handheld. Please press the hotsync button if you have not done so already." ), mainWidget, "fInfoText" );
	fInfoText->setAlignment( QLabel::WordBreak );

	fStatusGroup = new QGroupBox( i18n("Status"), mainWidget, "fStatusGroup" );
	fStatusGroup->setColumnLayout(0, Qt::Vertical );
	fStatusGroupLayout = new QGridLayout( fStatusGroup->layout() );

	fStatus = new QLabel( i18n("Autodetection not yet started..."), fStatusGroup, "fStatus" );
	fStatus->setAlignment( QLabel::WordBreak );
	fStatusGroupLayout->addWidget( fStatus, 0, 0 );

	fProgress = new KProgress( 60, fStatusGroup, "fProgress" );
	fStatusGroupLayout->addWidget( fProgress, 1, 0 );

	fResultsGroup = new QGroupBox( i18n( "Detected Values" ), mainWidget, "fResultsGroup" );
	fResultsGroup->setEnabled( FALSE );
	fResultsGroup->setColumnLayout(0, Qt::Vertical );
	fResultsGroupLayout = new QGridLayout( fResultsGroup->layout() );
	fResultsGroupLayout->setAlignment( Qt::AlignTop );

	fUserLabel = new QLabel( i18n( "Handheld user:" ), fResultsGroup, "fUserLabel" );
	fUserLabel->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, fUserLabel->sizePolicy().hasHeightForWidth() ) );
	fResultsGroupLayout->addWidget( fUserLabel, 0, 0 );

	fDeviceLabel = new QLabel( i18n( "Device:" ), fResultsGroup, "fDeviceLabel" );
	fResultsGroupLayout->addWidget( fDeviceLabel, 1, 0 );

	fUser = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fUser" );
	fResultsGroupLayout->addWidget( fUser, 0, 1 );

	fDevice = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fDevice" );
	fResultsGroupLayout->addWidget( fDevice, 1, 1 );

	resize( QSize(459, 298).expandedTo(minimumSizeHint()) );
	clearWState( WState_Polished );
	enableButtonOK(false);

	mDevicesToProbe[0] << "/dev/pilot";
	mDevicesToProbe[1] <<"/dev/ttyS0"<<"/dev/ttyS2"
	                <<"/dev/tts/0"<<"/dev/tts/2"
	                <<"/dev/ttyUSB0"<<"/dev/ttyUSB2"
	                <<"/dev/usb/tts/0"<<"/dev/usb/tts/2"
	                <<"/dev/cuaa0"<<"/dev/cuaa2"
	                <<"/dev/ucom0"<<"/dev/ucom2";
	mDevicesToProbe[2] <<"/dev/ttyS1"<<"/dev/ttyS3"
	                <<"/dev/tts/1"<<"/dev/tts/3"
	                <<"/dev/ttyUSB1"<<"/dev/ttyUSB3"
	                <<"/dev/usb/tts/1"<<"/dev/usb/tts/3"
	                <<"/dev/cuaa1"<<"/dev/cuaa3"
	                <<"/dev/ucom1"<<"/dev/ucom3";

	fProcessEventsTimer = new QTimer( this );
	fTimeoutTimer = new QTimer( this );
	fProgressTimer = new QTimer( this );
	fRotateLinksTimer = new QTimer( this );
	connect( fProcessEventsTimer, SIGNAL(timeout()), this, SLOT(processEvents()) );
	connect( fTimeoutTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
	connect( fProgressTimer, SIGNAL(timeout()), this, SLOT( progress()) );
	connect( fRotateLinksTimer, SIGNAL(timeout()), this, SLOT( detect()) );
	connect( this, SIGNAL(finished()), this, SLOT(disconnectDevices()) );
}

ProbeDialog::~ProbeDialog()
{
}

void ProbeDialog::processEvents()
{
	FUNCTIONSETUP;
	KApplication::kApplication()->processEvents();
}

void ProbeDialog::progress()
{
	fProgress->advance(1);
}

int ProbeDialog::exec()
{
	mDetected = false;
	mUserName = "";
	mDevice = "";
	mUID = 0;
	QTimer::singleShot( 0, this, SLOT( startDetection() ) );
	return KDialogBase::exec();
}

void ProbeDialog::startDetection()
{
	FUNCTIONSETUP;

	disconnectDevices();
	fProgress->setProgress(0);
	fStatus->setText( i18n("Starting detection...") );
	QTimer::singleShot(0, this, SLOT(processEvents()) );
	processEvents();
	PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
	if (daemonStub) {
		daemonStub->stopListening();
	}
	KPILOT_DELETE(daemonStub);
	processEvents();
	if (!fTimeoutTimer->start( 30000, true ) ) kdDebug()<<"Could not start fTimeoutTimer"<<endl;
	if (!fProcessEventsTimer->start( 100, false ) ) kdDebug()<<"Could not start fProcessEventsTimer"<<endl;
	if (!fProgressTimer->start( 500, false) ) kdDebug()<<"Could not start Progress timer"<<endl;

	KPilotDeviceLink*link;
	for (int i=0; i<3; i++)
	{
		QStringList::iterator end(mDevicesToProbe[i].end());
		for (QStringList::iterator it=mDevicesToProbe[i].begin(); it!=end; ++it)
		{
			link = new KPilotDeviceLink();
#ifdef DEBUG
			kdDebug()<<"new kpilotDeviceLink for "<<(*it)<<endl;
#endif
			link->reset( *it );
			link->close();
//			mDeviceLinkMap[*it] = link;
			mDeviceLinks[i].append( link );
			connect( link, SIGNAL(deviceReady(KPilotDeviceLink*)), this, SLOT(connection(KPilotDeviceLink*)) );
			processEvents();
		}
	}
	fStatus->setText( i18n("Waiting for handheld to connect...") );
	mProbeDevicesIndex=0;

	detect();
	if (!fRotateLinksTimer->start( 3000, false) ) kdDebug()<<"Could not start Device link rotation timer"<<endl;
}

void ProbeDialog::detect(int i)
{
	FUNCTIONSETUP;
	PilotLinkList::iterator end(mDeviceLinks[mProbeDevicesIndex].end());
	for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
	{
		if (*it) (*it)->close();
	}
	mProbeDevicesIndex = i;
	end=mDeviceLinks[mProbeDevicesIndex].end();
	for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
	{
		if (*it) (*it)->reset();
	}
}

void ProbeDialog::detect()
{
	detect( (mProbeDevicesIndex+1)%3 );
}

void ProbeDialog::timeout()
{
	disconnectDevices();
	if (!mDetected) fStatus->setText( i18n("Timeout reached, could not detect a handheld.") );
}

void ProbeDialog::connection( KPilotDeviceLink*lnk)
{
	FUNCTIONSETUP;

	if (!lnk) return;
	KPilotUser*usr( lnk->getPilotUser() );

	mUserName = usr->getUserName();
	mUID = usr->getUserID();
	mDevice = lnk->pilotPath();
	lnk->endOfSync();

	QTimer::singleShot(0, this, SLOT(disconnectDevices()));
	fStatus->setText( i18n("Found a connected device on %1").arg(mDevice) );
	fUser->setText( mUserName );
	fDevice->setText( mDevice );
	mDetected = true;

	fResultsGroup->setEnabled( true );
	enableButtonOK(true);
}

void ProbeDialog::disconnectDevices()
{
	FUNCTIONSETUP;

	if (!mDetected) fStatus->setText( i18n("Disconnected from all devices") );
	fProcessEventsTimer->stop( );
	fTimeoutTimer->stop();
	fProgressTimer->stop();
	fRotateLinksTimer->stop();
	fProgress->setProgress(fProgress->maxValue());
	for (int i=0; i<3; ++i)
	{
		PilotLinkList::iterator end(mDeviceLinks[i].end());
		for (PilotLinkList::iterator it=mDeviceLinks[i].begin(); it!=end; ++it)
		{
			(*it)->close();
			KPILOT_DELETE(*it);
		}
		mDeviceLinks[i].clear();
	}

	PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
	if (daemonStub)
	{
		daemonStub->startListening();
	}
	KPILOT_DELETE(daemonStub);
}

<commit_msg>Set the progressbar to 100 steps and adjust the timer accordingly<commit_after>/* conduitConfigDialog.cc                KPilot
**
** Copyright (C) 2004 by Dan Pilone
** Written 2004 by Reinhold Kainhofer
**
** This file defines a .ui-based configuration dialog for conduits.
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
** MA 02111-1307, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include <qlayout.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qvbox.h>
#include <qtimer.h>
#include <qmap.h>
#include <qvaluelist.h>

#include <kmessagebox.h>
#include <kglobal.h>
#include <klocale.h>
#include <kconfigskeleton.h>
#include <kapplication.h>
#include <kprogress.h>

#include "kpilotConfig.h"
#include "pilotUser.h"
#include "pilotSysInfo.h"
#include "options.h"
#include "kpilotlink.h"

#include "kpilotProbeDialog.moc"
#ifndef __PILOTDAEMONDCOP_STUB__
#include "pilotDaemonDCOP_stub.h"
#endif

/*
We can't connect to /dev/ttyUSB0 and /dev/ttyUSB1 at the same time, because that will lock up kpilot completely. In particular, it gets a connection on /dev/ttyUSB0, which it processes, and while processing, a connection on USB1 is also detected. However, when kpilot gets 'round to process it, the link is already closed, and pi_connect hangs forever.

Now, I split up the list of devices to probe into three list, one holding /dev/pilot, the second holding all /dev/*0 and /dev/*2 (e.g. /dev/ttyUSB0 and /dev/ttyUSB2), and finally a third holding the remaining /dev/*1 and /dev/*3 devices. Each of these three sets of devices is activated for a few seconds, and then the next set is probed. This way, I ensure that kpilot never listens on /dev/ttyUSB0 and /dev/ttyUSB1 at the same time.

Now the first detection works fine. However, it seems the Linux kernel has another problem with /dev/ttyUSB0. I have a Clie, which uses ttyUSB0, and as soon as the wizard tries to listen on ttyUSB1 (after it detected the handheld on ttyUSB0 already), the kernel writes a warning message to the syslog:
visor ttyUSB1: Device lied about number of ports, please use a lower one.

If I continue autodetection once again afterwards, the visor module kind of crashes. lsmod shows an impossible usage count for the module:
reinhold@einstein:/kde/builddir$ lsmod
Module                  Size  Used by
visor                  17164  4294967294
usbserial              30704  1 visor

After that, the kernel doesn't detect the device ever again (until the computer is rebootet), and the module can't be unloaded.
*/

ProbeDialog::ProbeDialog(QWidget *parent, const char *n) :
	KDialogBase(parent, n, true, i18n("Autodetecting Your Handheld"), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Cancel, true, i18n("Restart detection...")),
	mDetected(false), mUserName(""), mDevice(""), mUID(0)
{
	QVBox *mainWidget = makeVBoxMainWidget();

	fInfoText = new QLabel( i18n( "KPilot is now trying to automatically detect the device of your handheld. Please press the hotsync button if you have not done so already." ), mainWidget, "fInfoText" );
	fInfoText->setAlignment( QLabel::WordBreak );

	fStatusGroup = new QGroupBox( i18n("Status"), mainWidget, "fStatusGroup" );
	fStatusGroup->setColumnLayout(0, Qt::Vertical );
	fStatusGroupLayout = new QGridLayout( fStatusGroup->layout() );

	fStatus = new QLabel( i18n("Autodetection not yet started..."), fStatusGroup, "fStatus" );
	fStatus->setAlignment( QLabel::WordBreak );
	fStatusGroupLayout->addWidget( fStatus, 0, 0 );

	fProgress = new KProgress( 100, fStatusGroup, "fProgress" );
	fStatusGroupLayout->addWidget( fProgress, 1, 0 );

	fResultsGroup = new QGroupBox( i18n( "Detected Values" ), mainWidget, "fResultsGroup" );
	fResultsGroup->setEnabled( FALSE );
	fResultsGroup->setColumnLayout(0, Qt::Vertical );
	fResultsGroupLayout = new QGridLayout( fResultsGroup->layout() );
	fResultsGroupLayout->setAlignment( Qt::AlignTop );

	fUserLabel = new QLabel( i18n( "Handheld user:" ), fResultsGroup, "fUserLabel" );
	fUserLabel->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, fUserLabel->sizePolicy().hasHeightForWidth() ) );
	fResultsGroupLayout->addWidget( fUserLabel, 0, 0 );

	fDeviceLabel = new QLabel( i18n( "Device:" ), fResultsGroup, "fDeviceLabel" );
	fResultsGroupLayout->addWidget( fDeviceLabel, 1, 0 );

	fUser = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fUser" );
	fResultsGroupLayout->addWidget( fUser, 0, 1 );

	fDevice = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fDevice" );
	fResultsGroupLayout->addWidget( fDevice, 1, 1 );

	resize( QSize(459, 298).expandedTo(minimumSizeHint()) );
	clearWState( WState_Polished );
	enableButtonOK(false);

	mDevicesToProbe[0] << "/dev/pilot";
	mDevicesToProbe[1] <<"/dev/ttyS0"<<"/dev/ttyS2"
	                <<"/dev/tts/0"<<"/dev/tts/2"
	                <<"/dev/ttyUSB0"<<"/dev/ttyUSB2"
	                <<"/dev/usb/tts/0"<<"/dev/usb/tts/2"
	                <<"/dev/cuaa0"<<"/dev/cuaa2"
	                <<"/dev/ucom0"<<"/dev/ucom2";
	mDevicesToProbe[2] <<"/dev/ttyS1"<<"/dev/ttyS3"
	                <<"/dev/tts/1"<<"/dev/tts/3"
	                <<"/dev/ttyUSB1"<<"/dev/ttyUSB3"
	                <<"/dev/usb/tts/1"<<"/dev/usb/tts/3"
	                <<"/dev/cuaa1"<<"/dev/cuaa3"
	                <<"/dev/ucom1"<<"/dev/ucom3";

	fProcessEventsTimer = new QTimer( this );
	fTimeoutTimer = new QTimer( this );
	fProgressTimer = new QTimer( this );
	fRotateLinksTimer = new QTimer( this );
	connect( fProcessEventsTimer, SIGNAL(timeout()), this, SLOT(processEvents()) );
	connect( fTimeoutTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
	connect( fProgressTimer, SIGNAL(timeout()), this, SLOT( progress()) );
	connect( fRotateLinksTimer, SIGNAL(timeout()), this, SLOT( detect()) );
	connect( this, SIGNAL(finished()), this, SLOT(disconnectDevices()) );
}

ProbeDialog::~ProbeDialog()
{
}

void ProbeDialog::processEvents()
{
	FUNCTIONSETUP;
	KApplication::kApplication()->processEvents();
}

void ProbeDialog::progress()
{
	fProgress->advance(1);
}

int ProbeDialog::exec()
{
	mDetected = false;
	mUserName = "";
	mDevice = "";
	mUID = 0;
	QTimer::singleShot( 0, this, SLOT( startDetection() ) );
	return KDialogBase::exec();
}

void ProbeDialog::startDetection()
{
	FUNCTIONSETUP;

	disconnectDevices();
	fProgress->setProgress(0);
	fStatus->setText( i18n("Starting detection...") );
	QTimer::singleShot(0, this, SLOT(processEvents()) );
	processEvents();
	PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
	if (daemonStub) {
		daemonStub->stopListening();
	}
	KPILOT_DELETE(daemonStub);
	processEvents();
	if (!fTimeoutTimer->start( 30000, true ) ) kdDebug()<<"Could not start fTimeoutTimer"<<endl;
	if (!fProcessEventsTimer->start( 100, false ) ) kdDebug()<<"Could not start fProcessEventsTimer"<<endl;
	if (!fProgressTimer->start( 300, false) ) kdDebug()<<"Could not start Progress timer"<<endl;

	KPilotDeviceLink*link;
	for (int i=0; i<3; i++)
	{
		QStringList::iterator end(mDevicesToProbe[i].end());
		for (QStringList::iterator it=mDevicesToProbe[i].begin(); it!=end; ++it)
		{
			link = new KPilotDeviceLink();
#ifdef DEBUG
			kdDebug()<<"new kpilotDeviceLink for "<<(*it)<<endl;
#endif
			link->reset( *it );
			link->close();
//			mDeviceLinkMap[*it] = link;
			mDeviceLinks[i].append( link );
			connect( link, SIGNAL(deviceReady(KPilotDeviceLink*)), this, SLOT(connection(KPilotDeviceLink*)) );
			processEvents();
		}
	}
	fStatus->setText( i18n("Waiting for handheld to connect...") );
	mProbeDevicesIndex=0;

	detect();
	if (!fRotateLinksTimer->start( 3000, false) ) kdDebug()<<"Could not start Device link rotation timer"<<endl;
}

void ProbeDialog::detect(int i)
{
	FUNCTIONSETUP;
	PilotLinkList::iterator end(mDeviceLinks[mProbeDevicesIndex].end());
	for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
	{
		if (*it) (*it)->close();
	}
	mProbeDevicesIndex = i;
	end=mDeviceLinks[mProbeDevicesIndex].end();
	for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
	{
		if (*it) (*it)->reset();
	}
}

void ProbeDialog::detect()
{
	detect( (mProbeDevicesIndex+1)%3 );
}

void ProbeDialog::timeout()
{
	disconnectDevices();
	if (!mDetected) fStatus->setText( i18n("Timeout reached, could not detect a handheld.") );
}

void ProbeDialog::connection( KPilotDeviceLink*lnk)
{
	FUNCTIONSETUP;

	if (!lnk) return;
	KPilotUser*usr( lnk->getPilotUser() );

	mUserName = usr->getUserName();
	mUID = usr->getUserID();
	mDevice = lnk->pilotPath();
	lnk->endOfSync();

	QTimer::singleShot(0, this, SLOT(disconnectDevices()));
	fStatus->setText( i18n("Found a connected device on %1").arg(mDevice) );
	fUser->setText( mUserName );
	fDevice->setText( mDevice );
	mDetected = true;

	fResultsGroup->setEnabled( true );
	enableButtonOK(true);
}

void ProbeDialog::disconnectDevices()
{
	FUNCTIONSETUP;

	if (!mDetected) fStatus->setText( i18n("Disconnected from all devices") );
	fProcessEventsTimer->stop( );
	fTimeoutTimer->stop();
	fProgressTimer->stop();
	fRotateLinksTimer->stop();
	fProgress->setProgress(fProgress->maxValue());
	for (int i=0; i<3; ++i)
	{
		PilotLinkList::iterator end(mDeviceLinks[i].end());
		for (PilotLinkList::iterator it=mDeviceLinks[i].begin(); it!=end; ++it)
		{
			(*it)->close();
			KPILOT_DELETE(*it);
		}
		mDeviceLinks[i].clear();
	}

	PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
	if (daemonStub)
	{
		daemonStub->startListening();
	}
	KPILOT_DELETE(daemonStub);
}

<|endoftext|>


<commit_before>#include <stdint.h>
#include <miopen/check_numerics.hpp>
#include <miopen/env.hpp>

namespace miopen {

MIOPEN_DECLARE_ENV_VAR(MIOPEN_CHECK_NUMERICS)

namespace CheckNumerics
{
    static const int Info                = 0x01;   // print results from all checks
    static const int Warn                = 0x02;   // print only if abnormal detected
    static const int Throw               = 0x04;   // MIOPEN_THROW on abnormal result
    static const int Abort               = 0x08;   // abort on abnormal result (to drop into debugger)
    static const int ComputeStats        = 0x10;  // Print mean/absmean/min/max (slow)
}
int CheckNumericsEnabled(int bitMask) { return (miopen::Value(MIOPEN_CHECK_NUMERICS{})) & bitMask; }

#define DTYPE     float
#define ACCUMTYPE float
// Must keep this structure synchronized with one in MIOpenCheckNumerics
struct CheckNumericsResult
{
    ACCUMTYPE _sum = 0.0f;
    ACCUMTYPE _absSum = 0.0f;
    DTYPE     _min = 0.0f;
    DTYPE     _max = 0.0f;

    int       _hasZero = 0;
    int       _hasNan = 0;
    int       _hasInf = 0;
};

static bool checkNumericsImpl(Handle &handle, const TensorDescriptor &dDesc, ConstData_t data, bool isInput)
{
    int numElements = dDesc.GetElementSize();

    // TODO - some constants we should get from the device:
    const int blockSize = 256;
    const int numBlocks = handle.GetMaxComputeUnits() * 6;
    const size_t numGlobalWorkItems = blockSize * numBlocks;

    const int computeStats = CheckNumericsEnabled(CheckNumerics::ComputeStats);

    CheckNumericsResult abnormal_h;

    auto abnormal_d = handle.Create(sizeof(CheckNumericsResult)); // TODO - someday avoid slow malloc/free here
    handle.WriteTo(&abnormal_h, abnormal_d, sizeof(CheckNumericsResult));

    std::string program_name = "MIOpenCheckNumerics.cl";
    std::string kernel_name  = "MIOpenCheckNumerics";
    const std::vector<size_t> vld = {size_t{blockSize}, size_t{1}, size_t{1}};
    const std::vector<size_t> vgd = {numGlobalWorkItems, size_t{1}, size_t{1}};
    handle.GetKernel("MIOpenCheckNumerics", "", program_name, kernel_name, vld, vgd, "" ) (data, numElements, abnormal_d.get(), computeStats);

    handle.ReadTo(&abnormal_h, abnormal_d, sizeof(CheckNumericsResult));

    bool isAbnormal = abnormal_h._hasNan || abnormal_h._hasInf;

    if ( CheckNumericsEnabled(CheckNumerics::Info) ||
        (CheckNumericsEnabled(CheckNumerics::Warn) && isAbnormal)) {

        std::cerr << (isAbnormal ? "warn:" : "info:")
                  << " checkNumerics on"
                  << " " << (isInput ? "INPUT ":"OUTPUT")
                  << " ptr=" << data
                  << " zeros=" << abnormal_h._hasZero
                  << " nans="  << abnormal_h._hasNan
                  << " infs="  << abnormal_h._hasInf;
        if (computeStats) {
            std::cerr << " mean="  << abnormal_h._sum / numElements
                      << " absmean="  << abnormal_h._absSum / numElements
                      << " min="  << abnormal_h._min
                      << " max="  << abnormal_h._max ;
        }
        std::cerr << "  {" << dDesc  << "}"
                  << "\n";
    }

    if (isAbnormal) {

        if (CheckNumericsEnabled(CheckNumerics::Throw)) {
            MIOPEN_THROW(miopenStatusInternalError, "abnormal checkNumerics result detected");
        }
        if (CheckNumericsEnabled(CheckNumerics::Abort)) {
            abort();
        }
    }

    return isAbnormal;
};

// Checks data for input
// Returns: 1 if abnormal value (inf or nan) detected in specified data, 0 otherwise
bool checkNumericsInput(Handle &handle, const TensorDescriptor &dDesc, ConstData_t data)
{
    return checkNumericsImpl(handle, dDesc, data, true);
}

// Synchronizes to wait for kernel to finish, then checks data for output:
// Returns: 1 if abnormal value (inf or nan) detected in specified data, 0 otherwise
bool checkNumericsOutput(Handle &handle, const TensorDescriptor &dDesc, Data_t data)
{
    handle.Finish();

    return checkNumericsImpl(handle, dDesc, data, false);
}

} // namespace miopen
<commit_msg>Print INPUT/OUTPUT for check_numerics exception.<commit_after>#include <stdint.h>
#include <miopen/check_numerics.hpp>
#include <miopen/env.hpp>

namespace miopen {

MIOPEN_DECLARE_ENV_VAR(MIOPEN_CHECK_NUMERICS)

namespace CheckNumerics
{
    static const int Info                = 0x01;   // print results from all checks
    static const int Warn                = 0x02;   // print only if abnormal detected
    static const int Throw               = 0x04;   // MIOPEN_THROW on abnormal result
    static const int Abort               = 0x08;   // abort on abnormal result (to drop into debugger)
    static const int ComputeStats        = 0x10;  // Print mean/absmean/min/max (slow)
}
int CheckNumericsEnabled(int bitMask) { return (miopen::Value(MIOPEN_CHECK_NUMERICS{})) & bitMask; }

#define DTYPE     float
#define ACCUMTYPE float
// Must keep this structure synchronized with one in MIOpenCheckNumerics
struct CheckNumericsResult
{
    ACCUMTYPE _sum = 0.0f;
    ACCUMTYPE _absSum = 0.0f;
    DTYPE     _min = 0.0f;
    DTYPE     _max = 0.0f;

    int       _hasZero = 0;
    int       _hasNan = 0;
    int       _hasInf = 0;
};

static bool checkNumericsImpl(Handle &handle, const TensorDescriptor &dDesc, ConstData_t data, bool isInput)
{
    int numElements = dDesc.GetElementSize();

    // TODO - some constants we should get from the device:
    const int blockSize = 256;
    const int numBlocks = handle.GetMaxComputeUnits() * 6;
    const size_t numGlobalWorkItems = blockSize * numBlocks;

    const int computeStats = CheckNumericsEnabled(CheckNumerics::ComputeStats);

    CheckNumericsResult abnormal_h;

    auto abnormal_d = handle.Create(sizeof(CheckNumericsResult)); // TODO - someday avoid slow malloc/free here
    handle.WriteTo(&abnormal_h, abnormal_d, sizeof(CheckNumericsResult));

    std::string program_name = "MIOpenCheckNumerics.cl";
    std::string kernel_name  = "MIOpenCheckNumerics";
    const std::vector<size_t> vld = {size_t{blockSize}, size_t{1}, size_t{1}};
    const std::vector<size_t> vgd = {numGlobalWorkItems, size_t{1}, size_t{1}};
    handle.GetKernel("MIOpenCheckNumerics", "", program_name, kernel_name, vld, vgd, "" ) (data, numElements, abnormal_d.get(), computeStats);

    handle.ReadTo(&abnormal_h, abnormal_d, sizeof(CheckNumericsResult));

    bool isAbnormal = abnormal_h._hasNan || abnormal_h._hasInf;

    if ( CheckNumericsEnabled(CheckNumerics::Info) ||
        (CheckNumericsEnabled(CheckNumerics::Warn) && isAbnormal)) {

        std::cerr << (isAbnormal ? "warn:" : "info:")
                  << " checkNumerics on"
                  << " " << (isInput ? "INPUT ":"OUTPUT")
                  << " ptr=" << data
                  << " zeros=" << abnormal_h._hasZero
                  << " nans="  << abnormal_h._hasNan
                  << " infs="  << abnormal_h._hasInf;
        if (computeStats) {
            std::cerr << " mean="  << abnormal_h._sum / numElements
                      << " absmean="  << abnormal_h._absSum / numElements
                      << " min="  << abnormal_h._min
                      << " max="  << abnormal_h._max ;
        }
        std::cerr << "  {" << dDesc  << "}"
                  << "\n";
    }

    if (isAbnormal) {

        if (CheckNumericsEnabled(CheckNumerics::Throw)) {
            if (isInput) {
                MIOPEN_THROW(miopenStatusInternalError, "abnormal checkNumerics result detected on INPUT");
            } else {
                MIOPEN_THROW(miopenStatusInternalError, "abnormal checkNumerics result detected on OUTPUT");
            }
        }
        if (CheckNumericsEnabled(CheckNumerics::Abort)) {
            abort();
        }
    }

    return isAbnormal;
};

// Checks data for input
// Returns: 1 if abnormal value (inf or nan) detected in specified data, 0 otherwise
bool checkNumericsInput(Handle &handle, const TensorDescriptor &dDesc, ConstData_t data)
{
    return checkNumericsImpl(handle, dDesc, data, true);
}

// Synchronizes to wait for kernel to finish, then checks data for output:
// Returns: 1 if abnormal value (inf or nan) detected in specified data, 0 otherwise
bool checkNumericsOutput(Handle &handle, const TensorDescriptor &dDesc, Data_t data)
{
    handle.Finish();

    return checkNumericsImpl(handle, dDesc, data, false);
}

} // namespace miopen
<|endoftext|>


<commit_before>#include <cmath>
#include <complex>
#include <limits>

#include "Tools/Exception/exception.hpp"

#include "Modem_PAM.hpp"

namespace aff3ct
{
namespace module
{
/*
 * Constructor / Destructor
 */
template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
Modem_PAM<B,R,Q,MAX>
::Modem_PAM(const int N, const R sigma, const int bits_per_symbol, const bool disable_sig2, const int n_frames,
            const std::string name)
: Modem<B,R,Q>(N,
               (int)std::ceil((float)N / (float)bits_per_symbol),
               sigma,
               n_frames,
               name),
  bits_per_symbol(bits_per_symbol),
  nbr_symbols    (1 << bits_per_symbol),
  sqrt_es        ((R)std::sqrt((this->nbr_symbols * this->nbr_symbols - 1.0) / 3.0)),
  disable_sig2   (disable_sig2),
  constellation  (nbr_symbols)
{
	mipp::vector<B> bits(this->bits_per_symbol);

	for (auto j = 0; j < this->nbr_symbols; j++)
	{
		for (auto l = 0; l < this->bits_per_symbol; l++)
			bits[l] = (j >> l) & 1;

		this->constellation[j] = this->bits_to_symbol(&bits[0]);
	}
}

template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
Modem_PAM<B,R,Q,MAX>
::~Modem_PAM()
{
}

/*
 * Mapping function
 */
template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
R Modem_PAM<B,R,Q,MAX>
::bits_to_symbol(const B* bits) const
 {
	auto bps = this->bits_per_symbol;

	auto symbol = (R)1.0 - ((R)bits[0] + (R)bits[0]);
	for (auto j = 1; j < bps; j++)
		symbol = ((R)1.0 - ((R)bits[j] + (R)bits[j])) * ((1 << j) - symbol);

	return symbol / this->sqrt_es;
 }

/*
 * Modem
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_modulate(const B *X_N1, R *X_N2, const int frame_id)
{
	auto size_in  = this->N;
	auto size_out = this->N_mod;
	auto bps      = this->bits_per_symbol;

	auto main_loop_size = size_in / bps;
	for (auto i = 0; i < main_loop_size; i++)
	{
		// compute the symbol "on the fly"
		// auto symbol = bits_to_symbol(&X_N1[i*bps]);

		// determine the symbol with a lookup table
		unsigned idx = 0;
		for (auto j = 0; j < bps; j++)
			idx += unsigned(unsigned(1 << j) * X_N1[i * bps +j]);
		auto symbol = this->constellation[idx];

		X_N2[i] = symbol;
	}

	// last elements if "size_in" is not a multiple of the number of bits per symbol
	if (main_loop_size * bps < size_in)
	{
		unsigned idx = 0;
		for (auto j = 0; j < size_in - (main_loop_size * bps); j++)
			idx += unsigned(unsigned(1 << j) * X_N1[main_loop_size * bps +j]);
		auto symbol = this->constellation[idx];

		X_N2[size_out -1] = symbol;
	}
}

/*
 * Filter
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_filter(const R *Y_N1, R *Y_N2, const int frame_id)
{
	std::copy(Y_N1, Y_N1 + this->N_fil, Y_N2);
}

/*
 * Demodulator
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate(const Q *Y_N1, Q *Y_N2, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)(1.0 / (this->sigma * this->sigma));

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -(Y_N1[k] - (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)this->constellation[j]) * inv_sigma2);
			else
				L1 = MAX(L1, -(Y_N1[k] - (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)this->constellation[j]) * inv_sigma2);

		Y_N2[n] = (L0 - L1);
	}
}

/*
 * Demodulator
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate_with_gains(const Q *Y_N1, const R *H_N, Q *Y_N2, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)(1.0 / (this->sigma * this->sigma));

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -(Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) * inv_sigma2);
			else
				L1 = MAX(L1, -(Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) * inv_sigma2);

		Y_N2[n] = (L0 - L1);
	}
}

template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate(const Q *Y_N1, const Q *Y_N2, Q *Y_N3, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)1.0 / (this->sigma * this->sigma);

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
		{
			auto tempL  = (Q)((Y_N1[k] - this->constellation[j]) *
			                  (Y_N1[k] - this->constellation[j]) * inv_sigma2);

			for (auto l = 0; l < b; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			for (auto l = b +1; l < this->bits_per_symbol; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -tempL);
			else
				L1 = MAX(L1, -tempL);
		}

		Y_N3[n] = (L0 - L1);
	}
}

template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate_with_gains(const Q *Y_N1, const R *H_N, const Q *Y_N2, Q *Y_N3, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)1.0 / (this->sigma * this->sigma);

	for (auto n = 0; n < size; n++) // boucle sur les LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
		{
			auto tempL = (Q)((Y_N1[k] - (Q)H_N[k] * this->constellation[j]) *
			                 (Y_N1[k] - (Q)H_N[k] * this->constellation[j]) * inv_sigma2);

			for (auto l = 0; l < b; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			for (auto l = b +1; l < this->bits_per_symbol; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -tempL);
			else
				L1 = MAX(L1, -tempL);
		}

		Y_N3[n] = (L0 - L1);
	}
}
}
}
<commit_msg>Factor 2 for real modulations.<commit_after>#include <cmath>
#include <complex>
#include <limits>

#include "Tools/Exception/exception.hpp"

#include "Modem_PAM.hpp"

namespace aff3ct
{
namespace module
{
/*
 * Constructor / Destructor
 */
template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
Modem_PAM<B,R,Q,MAX>
::Modem_PAM(const int N, const R sigma, const int bits_per_symbol, const bool disable_sig2, const int n_frames,
            const std::string name)
: Modem<B,R,Q>(N,
               (int)std::ceil((float)N / (float)bits_per_symbol),
               sigma,
               n_frames,
               name),
  bits_per_symbol(bits_per_symbol),
  nbr_symbols    (1 << bits_per_symbol),
  sqrt_es        ((R)std::sqrt((this->nbr_symbols * this->nbr_symbols - 1.0) / 3.0)),
  disable_sig2   (disable_sig2),
  constellation  (nbr_symbols)
{
	mipp::vector<B> bits(this->bits_per_symbol);

	for (auto j = 0; j < this->nbr_symbols; j++)
	{
		for (auto l = 0; l < this->bits_per_symbol; l++)
			bits[l] = (j >> l) & 1;

		this->constellation[j] = this->bits_to_symbol(&bits[0]);
	}
}

template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
Modem_PAM<B,R,Q,MAX>
::~Modem_PAM()
{
}

/*
 * Mapping function
 */
template <typename B, typename R, typename Q, tools::proto_max<Q> MAX>
R Modem_PAM<B,R,Q,MAX>
::bits_to_symbol(const B* bits) const
 {
	auto bps = this->bits_per_symbol;

	auto symbol = (R)1.0 - ((R)bits[0] + (R)bits[0]);
	for (auto j = 1; j < bps; j++)
		symbol = ((R)1.0 - ((R)bits[j] + (R)bits[j])) * ((1 << j) - symbol);

	return symbol / this->sqrt_es;
 }

/*
 * Modem
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_modulate(const B *X_N1, R *X_N2, const int frame_id)
{
	auto size_in  = this->N;
	auto size_out = this->N_mod;
	auto bps      = this->bits_per_symbol;

	auto main_loop_size = size_in / bps;
	for (auto i = 0; i < main_loop_size; i++)
	{
		// compute the symbol "on the fly"
		// auto symbol = bits_to_symbol(&X_N1[i*bps]);

		// determine the symbol with a lookup table
		unsigned idx = 0;
		for (auto j = 0; j < bps; j++)
			idx += unsigned(unsigned(1 << j) * X_N1[i * bps +j]);
		auto symbol = this->constellation[idx];

		X_N2[i] = symbol;
	}

	// last elements if "size_in" is not a multiple of the number of bits per symbol
	if (main_loop_size * bps < size_in)
	{
		unsigned idx = 0;
		for (auto j = 0; j < size_in - (main_loop_size * bps); j++)
			idx += unsigned(unsigned(1 << j) * X_N1[main_loop_size * bps +j]);
		auto symbol = this->constellation[idx];

		X_N2[size_out -1] = symbol;
	}
}

/*
 * Filter
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_filter(const R *Y_N1, R *Y_N2, const int frame_id)
{
	std::copy(Y_N1, Y_N1 + this->N_fil, Y_N2);
}

/*
 * Demodulator
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate(const Q *Y_N1, Q *Y_N2, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)(1.0 / (2 * this->sigma * this->sigma));

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -(Y_N1[k] - (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)this->constellation[j]) * inv_sigma2);
			else
				L1 = MAX(L1, -(Y_N1[k] - (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)this->constellation[j]) * inv_sigma2);

		Y_N2[n] = (L0 - L1);
	}
}

/*
 * Demodulator
 */
template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate_with_gains(const Q *Y_N1, const R *H_N, Q *Y_N2, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)(1.0 / (2 * this->sigma * this->sigma));

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -(Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) * inv_sigma2);
			else
				L1 = MAX(L1, -(Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) *
				              (Y_N1[k] - (Q)H_N[k] * (Q)this->constellation[j]) * inv_sigma2);

		Y_N2[n] = (L0 - L1);
	}
}

template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate(const Q *Y_N1, const Q *Y_N2, Q *Y_N3, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)1.0 / (2 * this->sigma * this->sigma);

	for (auto n = 0; n < size; n++) // loop upon the LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
		{
			auto tempL  = (Q)((Y_N1[k] - this->constellation[j]) *
			                  (Y_N1[k] - this->constellation[j]) * inv_sigma2);

			for (auto l = 0; l < b; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			for (auto l = b +1; l < this->bits_per_symbol; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -tempL);
			else
				L1 = MAX(L1, -tempL);
		}

		Y_N3[n] = (L0 - L1);
	}
}

template <typename B,typename R, typename Q, tools::proto_max<Q> MAX>
void Modem_PAM<B,R,Q,MAX>
::_demodulate_with_gains(const Q *Y_N1, const R *H_N, const Q *Y_N2, Q *Y_N3, const int frame_id)
{
	if (typeid(R) != typeid(Q))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (typeid(Q) != typeid(float) && typeid(Q) != typeid(double))
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	auto size       = this->N;
	auto inv_sigma2 = disable_sig2 ? (Q)1.0 : (Q)1.0 / (2 * this->sigma * this->sigma);

	for (auto n = 0; n < size; n++) // boucle sur les LLRs
	{
		auto L0 = -std::numeric_limits<Q>::infinity();
		auto L1 = -std::numeric_limits<Q>::infinity();
		auto b  = n % this->bits_per_symbol; // bit position in the symbol
		auto k  = n / this->bits_per_symbol; // symbol position

		for (auto j = 0; j < this->nbr_symbols; j++)
		{
			auto tempL = (Q)((Y_N1[k] - (Q)H_N[k] * this->constellation[j]) *
			                 (Y_N1[k] - (Q)H_N[k] * this->constellation[j]) * inv_sigma2);

			for (auto l = 0; l < b; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			for (auto l = b +1; l < this->bits_per_symbol; l++)
				tempL += (j & (1 << l)) * Y_N2[k * this->bits_per_symbol +l];

			if ((j & (1 << b)) == 0)
				L0 = MAX(L0, -tempL);
			else
				L1 = MAX(L1, -tempL);
		}

		Y_N3[n] = (L0 - L1);
	}
}
}
}
<|endoftext|>


<commit_before>/* Copyright (c) 2009 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 <stdio.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>

#include "BenchUtil.h"
#include "Crc32C.h"
#include "RamCloud.h"
#include "ObjectFinder.h"
#include "OptionParser.h"
#include "Tub.h"

using namespace RAMCloud;

/*
 * If true, add the table and object ids to every object, calculate and
 * append a checksum, and verify the whole package when recovery is done.
 * The crc is the first 4 bytes of the object. The tableId and objectId
 * are the last 16 bytes.
 */
bool verify = false;

/*
 * Speed up recovery insertion with the single-shot FillWithTestData RPC.
 */
bool fillWithTestData = false;

void
runRecovery(RamCloud& client,
            int count, uint32_t objectDataSize,
            int tableCount,
            int tableSkip)
{
    if (verify && objectDataSize < 20)
        DIE("need >= 20 byte objects to do verification!");
    if (verify && fillWithTestData)
        DIE("verify not supported with fillWithTestData");

    char tableName[20];
    int tables[tableCount];

    for (int t = 0; t < tableCount; t++) {
        snprintf(tableName, sizeof(tableName), "%d", t);
        client.createTable(tableName);
        tables[t] = client.openTable(tableName);

        // Create tables on the other masters so we skip back around to the
        // first in round-robin order to create multiple tables in the same
        // will
        for (int tt = 0; tt < tableSkip; tt++) {
            snprintf(tableName, sizeof(tableName), "junk%d.%d", t, tt);
            client.createTable(tableName);
        }
    }

    LOG(NOTICE, "Performing %u inserts of %u byte objects",
        count * tableCount, objectDataSize);

    if (fillWithTestData) {
        LOG(NOTICE, "Using the fillWithTestData rpc on a single master");
        uint64_t b = rdtsc();
        MasterClient master(client.objectFinder.lookup(0, 0));
        master.fillWithTestData(count * tableCount, objectDataSize);
        LOG(NOTICE, "%d inserts took %lu ticks",
            count * tableCount, rdtsc() - b);
        LOG(NOTICE, "avg insert took %lu ticks",
                    (rdtsc() - b) / count / tableCount);
    } else {
        char val[objectDataSize];
        memset(val, 0xcc, objectDataSize);
        Crc32C checksumBasis;
        checksumBasis.update(&val[4], objectDataSize - 20);
        Tub<RamCloud::Create> createRpcs[8];
        uint64_t b = rdtsc();
        for (int j = 0; j < count - 1; j++) {
            for (int t = 0; t < tableCount; t++) {
                auto& createRpc = createRpcs[(j * tableCount + t) %
                                             arrayLength(createRpcs)];
                if (createRpc)
                    (*createRpc)();

                if (verify) {
                    uint32_t *crcPtr = reinterpret_cast<uint32_t*>(&val[0]);
                    uint64_t *tableIdPtr =
                        reinterpret_cast<uint64_t*>(&val[objectDataSize-16]);
                    uint64_t *objectIdPtr =
                        reinterpret_cast<uint64_t*>(&val[objectDataSize-8]);
                    *tableIdPtr = tables[t];
                    *objectIdPtr = j;
                    Crc32C checksum = checksumBasis;
                    checksum.update(&val[objectDataSize-16], 16);
                    *crcPtr = checksum.getResult();
                }

                createRpc.construct(client,
                                    tables[t],
                                    static_cast<void*>(val), objectDataSize,
                                    /* version = */static_cast<uint64_t*>(NULL),
                                    /* async = */ true);
            }
        }
        foreach (auto& createRpc, createRpcs) {
            if (createRpc)
                (*createRpc)();
        }
        client.create(tables[0], val, objectDataSize,
                      /* version = */ NULL,
                      /* async = */ false);
        LOG(NOTICE, "%d inserts took %lu ticks",
            count * tableCount, rdtsc() - b);
        LOG(NOTICE, "avg insert took %lu ticks",
            (rdtsc() - b) / count / tableCount);
    }

    // dump the tablet map
    for (int t = 0; t < tableCount; t++) {
        Transport::SessionRef session =
            client.objectFinder.lookup(tables[t], 0);
        LOG(NOTICE, "%s has table %u",
            session->getServiceLocator().c_str(), tables[t]);
    }

    // dump out coordinator rpc info
    client.ping();

    LOG(NOTICE, "- quiescing writes");
    client.coordinator.quiesce();

    Transport::SessionRef session = client.objectFinder.lookup(tables[0], 0);
    LOG(NOTICE, "--- hinting that the server is down: %s ---",
        session->getServiceLocator().c_str());

    uint64_t b = rdtsc();
    client.coordinator.hintServerDown(
        session->getServiceLocator().c_str());

    client.objectFinder.waitForAllTabletsNormal();

    Buffer nb;
    uint64_t stopTime = rdtsc();
    // Check a value in each table to make sure we're good
    for (int t = 0; t < tableCount; t++) {
        int table = tables[t];
        try {
            client.read(table, 0, &nb);
            if (t == 0)
                stopTime = rdtsc();
        } catch (...) {
        }
        LOG(NOTICE, "read recovered data on %s",
            session->getServiceLocator().c_str());

        session = client.objectFinder.lookup(tables[t], 0);
        LOG(NOTICE, "read value has length %u", nb.getTotalLength());
    }
    LOG(NOTICE, "Recovery completed in %lu ns",
        cyclesToNanoseconds(stopTime - b));

    b = rdtsc();
    if (verify) {
        LOG(NOTICE, "Verifying all data.");

        int total = count * tableCount;
        int tenPercent = total / 10;
        int logCount = 0;
        for (int j = 0; j < count - 1; j++) {
            for (int t = 0; t < tableCount; t++) {
                try {
                    client.read(tables[t], j, &nb);
                } catch (...) {
                    LOG(ERROR, "Failed to access object (tbl %d, obj %d)!",
                        tables[t], j);
                    continue;
                }
                const char* objData = nb.getStart<char>();
                uint32_t objBytes = nb.getTotalLength();

                if (objBytes != objectDataSize) {
                    LOG(ERROR, "Bad object size (tbl %d, obj %d)",
                        tables[t], j);
                } else {
                    Crc32C checksum;
                    checksum.update(&objData[4], objBytes - 4);
                    if (checksum.getResult() != *nb.getStart<uint32_t>()) {
                        LOG(ERROR, "Bad object checksum (tbl %d, obj %d)",
                            tables[t], j);
                    }
                }
            }

            logCount += tableCount;
            if (logCount >= tenPercent) {
                LOG(DEBUG, " -- %.2f%% done",
                    100.0 * (j * tableCount) / total);
                logCount = 0;
            }
        }

        LOG(NOTICE, "Verification took %lu ns",
            cyclesToNanoseconds(rdtsc() - b));
    }

    // dump out coordinator rpc info
    client.ping();
}

int
main(int argc, char *argv[])
try
{
    bool hintServerDown;
    int count;
    uint32_t objectDataSize;
    uint32_t tableCount;
    uint32_t skipCount;

    OptionsDescription clientOptions("Client");
    clientOptions.add_options()
        ("down,d",
         ProgramOptions::bool_switch(&hintServerDown),
         "Report the master we're talking to as down just before exit.")
        ("fast,f",
         ProgramOptions::bool_switch(&fillWithTestData),
         "Use a single fillWithTestData rpc to insert recovery objects.")
        ("tables,t",
         ProgramOptions::value<uint32_t>(&tableCount)->
            default_value(1),
         "The number of tables to create with number objects on the master.")
        ("skip,k",
         ProgramOptions::value<uint32_t>(&skipCount)->
            default_value(1),
         "The number of empty tables to create per real table."
         "An enormous hack to create partitions on the crashed master.")
        ("number,n",
         ProgramOptions::value<int>(&count)->
            default_value(1024),
         "The number of values to insert.")
        ("size,s",
         ProgramOptions::value<uint32_t>(&objectDataSize)->
            default_value(1024),
         "Number of bytes to insert per object during insert phase.")
        ("verify,v",
         ProgramOptions::bool_switch(&verify),
         "Verify the contents of all objects after recovery completes.");

    OptionParser optionParser(clientOptions, argc, argv);

    LOG(NOTICE, "client: Connecting to %s",
        optionParser.options.getCoordinatorLocator().c_str());

    RamCloud client(optionParser.options.getCoordinatorLocator().c_str());

    if (hintServerDown) {
        runRecovery(client, count, objectDataSize, tableCount, skipCount);
        return 0;
    }

    uint64_t b;

    b = rdtsc();
    client.createTable("test");
    uint32_t table;
    table = client.openTable("test");
    LOG(DEBUG, "create+open table took %lu ticks", rdtsc() - b);

    b = rdtsc();
    client.ping();
    LOG(DEBUG, "ping took %lu ticks on the client", rdtsc() - b);

    b = rdtsc();
    client.write(table, 42, "Hello, World!", 14);
    LOG(DEBUG, "write took %lu ticks", rdtsc() - b);

    b = rdtsc();
    const char *value = "0123456789012345678901234567890"
        "123456789012345678901234567890123456789";
    client.write(table, 43, value, downCast<uint32_t>(strlen(value) + 1));
    LOG(DEBUG, "write took %lu ticks", rdtsc() - b);

    Buffer buffer;
    b = rdtsc();
    uint32_t length;

    client.read(table, 43, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);

    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    client.read(table, 42, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);
    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    b = rdtsc();
    uint64_t id = 0xfffffff;
    id = client.create(table, "Hello, World?", 14);
    LOG(DEBUG, "insert took %lu ticks", rdtsc() - b);
    LOG(DEBUG, "Got back [%lu] id", id);

    b = rdtsc();
    client.read(table, id, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);
    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    char val[objectDataSize];
    memset(val, 0xcc, objectDataSize);
    id = 0xfffffff;

    LOG(NOTICE, "Performing %u inserts of %u byte objects",
        count, objectDataSize);
    b = rdtsc();
    for (int j = 0; j < count; j++)
        id = client.create(table, val, downCast<uint32_t>(strlen(val) + 1));
    LOG(DEBUG, "%d inserts took %lu ticks", count, rdtsc() - b);
    LOG(DEBUG, "avg insert took %lu ticks", (rdtsc() - b) / count);

    client.dropTable("test");

    return 0;
} catch (RAMCloud::ClientException& e) {
    fprintf(stderr, "RAMCloud exception: %s\n", e.str().c_str());
    return 1;
} catch (RAMCloud::Exception& e) {
    fprintf(stderr, "RAMCloud exception: %s\n", e.str().c_str());
    return 1;
}
<commit_msg>Fixed incorrect debug message<commit_after>/* Copyright (c) 2009 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 <stdio.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>

#include "BenchUtil.h"
#include "Crc32C.h"
#include "RamCloud.h"
#include "ObjectFinder.h"
#include "OptionParser.h"
#include "Tub.h"

using namespace RAMCloud;

/*
 * If true, add the table and object ids to every object, calculate and
 * append a checksum, and verify the whole package when recovery is done.
 * The crc is the first 4 bytes of the object. The tableId and objectId
 * are the last 16 bytes.
 */
bool verify = false;

/*
 * Speed up recovery insertion with the single-shot FillWithTestData RPC.
 */
bool fillWithTestData = false;

void
runRecovery(RamCloud& client,
            int count, uint32_t objectDataSize,
            int tableCount,
            int tableSkip)
{
    if (verify && objectDataSize < 20)
        DIE("need >= 20 byte objects to do verification!");
    if (verify && fillWithTestData)
        DIE("verify not supported with fillWithTestData");

    char tableName[20];
    int tables[tableCount];

    for (int t = 0; t < tableCount; t++) {
        snprintf(tableName, sizeof(tableName), "%d", t);
        client.createTable(tableName);
        tables[t] = client.openTable(tableName);

        // Create tables on the other masters so we skip back around to the
        // first in round-robin order to create multiple tables in the same
        // will
        for (int tt = 0; tt < tableSkip; tt++) {
            snprintf(tableName, sizeof(tableName), "junk%d.%d", t, tt);
            client.createTable(tableName);
        }
    }

    LOG(NOTICE, "Performing %u inserts of %u byte objects",
        count * tableCount, objectDataSize);

    if (fillWithTestData) {
        LOG(NOTICE, "Using the fillWithTestData rpc on a single master");
        uint64_t b = rdtsc();
        MasterClient master(client.objectFinder.lookup(0, 0));
        master.fillWithTestData(count * tableCount, objectDataSize);
        LOG(NOTICE, "%d inserts took %lu ticks",
            count * tableCount, rdtsc() - b);
        LOG(NOTICE, "avg insert took %lu ticks",
                    (rdtsc() - b) / count / tableCount);
    } else {
        char val[objectDataSize];
        memset(val, 0xcc, objectDataSize);
        Crc32C checksumBasis;
        checksumBasis.update(&val[4], objectDataSize - 20);
        Tub<RamCloud::Create> createRpcs[8];
        uint64_t b = rdtsc();
        for (int j = 0; j < count - 1; j++) {
            for (int t = 0; t < tableCount; t++) {
                auto& createRpc = createRpcs[(j * tableCount + t) %
                                             arrayLength(createRpcs)];
                if (createRpc)
                    (*createRpc)();

                if (verify) {
                    uint32_t *crcPtr = reinterpret_cast<uint32_t*>(&val[0]);
                    uint64_t *tableIdPtr =
                        reinterpret_cast<uint64_t*>(&val[objectDataSize-16]);
                    uint64_t *objectIdPtr =
                        reinterpret_cast<uint64_t*>(&val[objectDataSize-8]);
                    *tableIdPtr = tables[t];
                    *objectIdPtr = j;
                    Crc32C checksum = checksumBasis;
                    checksum.update(&val[objectDataSize-16], 16);
                    *crcPtr = checksum.getResult();
                }

                createRpc.construct(client,
                                    tables[t],
                                    static_cast<void*>(val), objectDataSize,
                                    /* version = */static_cast<uint64_t*>(NULL),
                                    /* async = */ true);
            }
        }
        foreach (auto& createRpc, createRpcs) {
            if (createRpc)
                (*createRpc)();
        }
        client.create(tables[0], val, objectDataSize,
                      /* version = */ NULL,
                      /* async = */ false);
        LOG(NOTICE, "%d inserts took %lu ticks",
            count * tableCount, rdtsc() - b);
        LOG(NOTICE, "avg insert took %lu ticks",
            (rdtsc() - b) / count / tableCount);
    }

    // dump the tablet map
    for (int t = 0; t < tableCount; t++) {
        Transport::SessionRef session =
            client.objectFinder.lookup(tables[t], 0);
        LOG(NOTICE, "%s has table %u",
            session->getServiceLocator().c_str(), tables[t]);
    }

    // dump out coordinator rpc info
    client.ping();

    LOG(NOTICE, "- quiescing writes");
    client.coordinator.quiesce();

    Transport::SessionRef session = client.objectFinder.lookup(tables[0], 0);
    LOG(NOTICE, "--- hinting that the server is down: %s ---",
        session->getServiceLocator().c_str());

    uint64_t b = rdtsc();
    client.coordinator.hintServerDown(
        session->getServiceLocator().c_str());

    client.objectFinder.waitForAllTabletsNormal();

    Buffer nb;
    uint64_t stopTime = rdtsc();
    // Check a value in each table to make sure we're good
    for (int t = 0; t < tableCount; t++) {
        int table = tables[t];
        try {
            client.read(table, 0, &nb);
            if (t == 0)
                stopTime = rdtsc();
        } catch (...) {
        }
        session = client.objectFinder.lookup(tables[t], 0);
        LOG(NOTICE, "recovered value read from %s has length %u",
            session->getServiceLocator().c_str(), nb.getTotalLength());
    }
    LOG(NOTICE, "Recovery completed in %lu ns",
        cyclesToNanoseconds(stopTime - b));

    b = rdtsc();
    if (verify) {
        LOG(NOTICE, "Verifying all data.");

        int total = count * tableCount;
        int tenPercent = total / 10;
        int logCount = 0;
        for (int j = 0; j < count - 1; j++) {
            for (int t = 0; t < tableCount; t++) {
                try {
                    client.read(tables[t], j, &nb);
                } catch (...) {
                    LOG(ERROR, "Failed to access object (tbl %d, obj %d)!",
                        tables[t], j);
                    continue;
                }
                const char* objData = nb.getStart<char>();
                uint32_t objBytes = nb.getTotalLength();

                if (objBytes != objectDataSize) {
                    LOG(ERROR, "Bad object size (tbl %d, obj %d)",
                        tables[t], j);
                } else {
                    Crc32C checksum;
                    checksum.update(&objData[4], objBytes - 4);
                    if (checksum.getResult() != *nb.getStart<uint32_t>()) {
                        LOG(ERROR, "Bad object checksum (tbl %d, obj %d)",
                            tables[t], j);
                    }
                }
            }

            logCount += tableCount;
            if (logCount >= tenPercent) {
                LOG(DEBUG, " -- %.2f%% done",
                    100.0 * (j * tableCount) / total);
                logCount = 0;
            }
        }

        LOG(NOTICE, "Verification took %lu ns",
            cyclesToNanoseconds(rdtsc() - b));
    }

    // dump out coordinator rpc info
    client.ping();
}

int
main(int argc, char *argv[])
try
{
    bool hintServerDown;
    int count;
    uint32_t objectDataSize;
    uint32_t tableCount;
    uint32_t skipCount;

    OptionsDescription clientOptions("Client");
    clientOptions.add_options()
        ("down,d",
         ProgramOptions::bool_switch(&hintServerDown),
         "Report the master we're talking to as down just before exit.")
        ("fast,f",
         ProgramOptions::bool_switch(&fillWithTestData),
         "Use a single fillWithTestData rpc to insert recovery objects.")
        ("tables,t",
         ProgramOptions::value<uint32_t>(&tableCount)->
            default_value(1),
         "The number of tables to create with number objects on the master.")
        ("skip,k",
         ProgramOptions::value<uint32_t>(&skipCount)->
            default_value(1),
         "The number of empty tables to create per real table."
         "An enormous hack to create partitions on the crashed master.")
        ("number,n",
         ProgramOptions::value<int>(&count)->
            default_value(1024),
         "The number of values to insert.")
        ("size,s",
         ProgramOptions::value<uint32_t>(&objectDataSize)->
            default_value(1024),
         "Number of bytes to insert per object during insert phase.")
        ("verify,v",
         ProgramOptions::bool_switch(&verify),
         "Verify the contents of all objects after recovery completes.");

    OptionParser optionParser(clientOptions, argc, argv);

    LOG(NOTICE, "client: Connecting to %s",
        optionParser.options.getCoordinatorLocator().c_str());

    RamCloud client(optionParser.options.getCoordinatorLocator().c_str());

    if (hintServerDown) {
        runRecovery(client, count, objectDataSize, tableCount, skipCount);
        return 0;
    }

    uint64_t b;

    b = rdtsc();
    client.createTable("test");
    uint32_t table;
    table = client.openTable("test");
    LOG(DEBUG, "create+open table took %lu ticks", rdtsc() - b);

    b = rdtsc();
    client.ping();
    LOG(DEBUG, "ping took %lu ticks on the client", rdtsc() - b);

    b = rdtsc();
    client.write(table, 42, "Hello, World!", 14);
    LOG(DEBUG, "write took %lu ticks", rdtsc() - b);

    b = rdtsc();
    const char *value = "0123456789012345678901234567890"
        "123456789012345678901234567890123456789";
    client.write(table, 43, value, downCast<uint32_t>(strlen(value) + 1));
    LOG(DEBUG, "write took %lu ticks", rdtsc() - b);

    Buffer buffer;
    b = rdtsc();
    uint32_t length;

    client.read(table, 43, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);

    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    client.read(table, 42, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);
    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    b = rdtsc();
    uint64_t id = 0xfffffff;
    id = client.create(table, "Hello, World?", 14);
    LOG(DEBUG, "insert took %lu ticks", rdtsc() - b);
    LOG(DEBUG, "Got back [%lu] id", id);

    b = rdtsc();
    client.read(table, id, &buffer);
    LOG(DEBUG, "read took %lu ticks", rdtsc() - b);
    length = buffer.getTotalLength();
    LOG(DEBUG, "Got back [%s] len %u",
        static_cast<const char*>(buffer.getRange(0, length)),
        length);

    char val[objectDataSize];
    memset(val, 0xcc, objectDataSize);
    id = 0xfffffff;

    LOG(NOTICE, "Performing %u inserts of %u byte objects",
        count, objectDataSize);
    b = rdtsc();
    for (int j = 0; j < count; j++)
        id = client.create(table, val, downCast<uint32_t>(strlen(val) + 1));
    LOG(DEBUG, "%d inserts took %lu ticks", count, rdtsc() - b);
    LOG(DEBUG, "avg insert took %lu ticks", (rdtsc() - b) / count);

    client.dropTable("test");

    return 0;
} catch (RAMCloud::ClientException& e) {
    fprintf(stderr, "RAMCloud exception: %s\n", e.str().c_str());
    return 1;
} catch (RAMCloud::Exception& e) {
    fprintf(stderr, "RAMCloud exception: %s\n", e.str().c_str());
    return 1;
}
<|endoftext|>


<commit_before>#include "binlog.h"

#include "common/asm_atomic.h"
#include "common/logging.h"

namespace galaxy {
namespace ins {

std::string log_data_file_name = "log.data";
std::string log_index_file_name = "log.index";

BinLogger::BinLogger(const std::string& data_dir) : log_data_file_(NULL),
													log_index_file_(NULL) {
    log_data_file_name = data_dir + "/" + log_data_file_name;
    log_index_file_name = data_dir + "/" + log_index_file_name;
    log_data_file_ =  fopen(log_data_file_name.c_str(), "a+");
    assert(log_data_file_);
    log_index_file_ = fopen(log_index_file_name.c_str(), "a+");
    assert(log_index_file_);
}

BinLogger::~BinLogger() {
	fclose(log_data_file_);
	fclose(log_index_file_);
}

bool BinLogger::ReadUntil(int64_t end_slot_index,
                          boost::function<void (const LogEntry& log_entry)> reader) {
    return true;
}

int64_t BinLogger::GetLength() {
    int64_t index_file_size = fseek(log_index_file_, 0 , SEEK_END);
    return index_file_size / sizeof(int64_t);
}

bool BinLogger::ReadSlot(int64_t slot_index, LogEntry* log_entry) {
	int64_t offset = slot_index * sizeof(int64_t);
	if (fseek(log_index_file_, offset, SEEK_SET) < 0) {
		LOG(FATAL, "seek file failed: %s", log_index_file_name.c_str());
		return false;
	}
	int64_t data_offset = 0 ;
	if (fread(&data_offset, sizeof(int64_t), 1, log_index_file_) != 1) {
		LOG(FATAL, "faild to read file %s", log_index_file_name.c_str());
		abort();
	}
	if (fseek(log_data_file_, data_offset, SEEK_SET) < 0) {
		LOG(FATAL, "seek file failed: %s", log_data_file_name.c_str());
		return false;
	}
	int64_t entry_len = 0;
	if (fread(&entry_len, sizeof(int64_t), 1, log_data_file_) != 1) {
		LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
		abort();
	}
	std::string buf;
	buf.resize(entry_len);
	if (fread(&buf[0], entry_len, 1, log_data_file_) !=1 ) {
		LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
		abort();
	}
	LoadLogEntry(buf, log_entry);
    return true;
}

void BinLogger::AppendEntry(const LogEntry& log_entry) {
	std::string buf;
	DumpLogEntry(log_entry, &buf);
	int64_t entry_len = buf.size();
	fseek(log_data_file_, 0, SEEK_END);
	int64_t data_cur_size = ftell(log_data_file_);

	if (fwrite(&entry_len, sizeof(int64_t), 1, log_data_file_) != 1) {
		LOG(FATAL, "write file %s faild", log_data_file_name.c_str());
		abort();
	}
	if (fwrite(&buf[0], buf.size(), 1, log_data_file_) != 1) {
		LOG(FATAL, "write file %s faild", log_data_file_name.c_str());
		abort();
	}
	if (fwrite(&data_cur_size, sizeof(int64_t), 1, log_index_file_) != 1) {
		LOG(FATAL, "write file %s faild", log_index_file_name.c_str());
		abort();
	}
}

void BinLogger::Truncate(int64_t start_slot_index) {

}

void BinLogger::DumpLogEntry(const LogEntry& log_entry, std::string* buf) {
	assert(buf);
	int32_t total_len = sizeof(uint8_t)
	                    + sizeof(int32_t) + log_entry.key.size()
	                    + sizeof(int32_t) + log_entry.value.size()
	                    + sizeof(int64_t);
	buf->resize(total_len);
	int32_t key_size = log_entry.key.size();
	int32_t value_size = log_entry.value.size();
	char* p = reinterpret_cast<char*>((*buf)[0]);
	p[0] = static_cast<uint8_t>(log_entry.op);
	p += sizeof(uint8_t);
	memcpy(p, static_cast<const void*>(&key_size), sizeof(int32_t));
	p += sizeof(int32_t);
	memcpy(p, static_cast<const void*>(log_entry.key.data()), log_entry.key.size());
	p += log_entry.key.size();
	memcpy(p, static_cast<const void*>(&value_size), sizeof(int32_t));
	p += sizeof(int32_t);
	memcpy(p, static_cast<const void*>(log_entry.value.data()), log_entry.value.size());
	p += log_entry.value.size();
	memcpy(p, static_cast<const void*>(&log_entry.term), sizeof(int64_t));
}

void BinLogger::LoadLogEntry(const std::string& buf, LogEntry* log_entry) {
	assert(log_entry);
	const char* p = buf.data();
	int32_t key_size = 0;
	int32_t value_size = 0;
	memcpy(static_cast<void*>(&log_entry->op), p, sizeof(uint8_t));
	p += sizeof(uint8_t);
	memcpy(static_cast<void*>(&key_size), p, sizeof(int32_t));
	log_entry->key.resize(key_size);
	p += sizeof(int32_t);
	memcpy(static_cast<void*>(&log_entry->key[0]), p, key_size);
	p += key_size;
	memcpy(static_cast<void*>(&value_size), p, sizeof(int32_t));
	log_entry->value.resize(value_size);
	p += sizeof(int32_t);
	memcpy(static_cast<void*>(&log_entry->value[0]), p, value_size);
	p += value_size;
	memcpy(static_cast<void*>(&log_entry->term), p , sizeof(int64_t));
}

} //namespace ins
} //namespace galaxy

<commit_msg>format fix<commit_after>#include "binlog.h"

#include "common/asm_atomic.h"
#include "common/logging.h"

namespace galaxy {
namespace ins {

std::string log_data_file_name = "log.data";
std::string log_index_file_name = "log.index";

BinLogger::BinLogger(const std::string& data_dir) : log_data_file_(NULL),
                                                    log_index_file_(NULL) {
    log_data_file_name = data_dir + "/" + log_data_file_name;
    log_index_file_name = data_dir + "/" + log_index_file_name;
    log_data_file_ =  fopen(log_data_file_name.c_str(), "a+");
    assert(log_data_file_);
    log_index_file_ = fopen(log_index_file_name.c_str(), "a+");
    assert(log_index_file_);
}

BinLogger::~BinLogger() {
    fclose(log_data_file_);
    fclose(log_index_file_);
}

bool BinLogger::ReadUntil(int64_t end_slot_index,
                          boost::function<void (const LogEntry& log_entry)> reader) {
    int64_t slot_count = GetLength();
    if (end_slot_index >= slot_count) {
        LOG(FATAL, "invalid end_slot_index: %ld >= %ld", end_slot_index, slot_count);
        return false;
    }
    LogEntry log_entry;
    int64_t entry_len = 0;
    if (fread(&entry_len, sizeof(int64_t), 1, log_data_file_) != 1) {
        LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
        abort();
    }
    std::string buf;
    buf.resize(entry_len);
    if (fread(&buf[0], entry_len, 1, log_data_file_) !=1 ) {
        LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
        abort();
    }
    LoadLogEntry(buf, &log_entry);
    reader(log_entry);
    return true;
}

int64_t BinLogger::GetLength() {
    int64_t index_file_size = fseek(log_index_file_, 0 , SEEK_END);
    return index_file_size / sizeof(int64_t);
}

bool BinLogger::ReadSlot(int64_t slot_index, LogEntry* log_entry) {
    int64_t offset = slot_index * sizeof(int64_t);
    if (fseek(log_index_file_, offset, SEEK_SET) < 0) {
        LOG(FATAL, "seek file failed: %s", log_index_file_name.c_str());
        return false;
    }
    int64_t data_offset = 0 ;
    if (fread(&data_offset, sizeof(int64_t), 1, log_index_file_) != 1) {
        LOG(FATAL, "faild to read file %s", log_index_file_name.c_str());
        abort();
    }
    if (fseek(log_data_file_, data_offset, SEEK_SET) < 0) {
        LOG(FATAL, "seek file failed: %s", log_data_file_name.c_str());
        return false;
    }
    int64_t entry_len = 0;
    if (fread(&entry_len, sizeof(int64_t), 1, log_data_file_) != 1) {
        LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
        abort();
    }
    std::string buf;
    buf.resize(entry_len);
    if (fread(&buf[0], entry_len, 1, log_data_file_) !=1 ) {
        LOG(FATAL, "faild to read file %s", log_data_file_name.c_str());
        abort();
    }
    LoadLogEntry(buf, log_entry);
    return true;
}

void BinLogger::AppendEntry(const LogEntry& log_entry) {
    std::string buf;
    DumpLogEntry(log_entry, &buf);
    int64_t entry_len = buf.size();
    fseek(log_data_file_, 0, SEEK_END);
    int64_t data_cur_size = ftell(log_data_file_);

    if (fwrite(&entry_len, sizeof(int64_t), 1, log_data_file_) != 1) {
        LOG(FATAL, "write file %s faild", log_data_file_name.c_str());
        abort();
    }
    if (fwrite(&buf[0], buf.size(), 1, log_data_file_) != 1) {
        LOG(FATAL, "write file %s faild", log_data_file_name.c_str());
        abort();
    }
    if (fwrite(&data_cur_size, sizeof(int64_t), 1, log_index_file_) != 1) {
        LOG(FATAL, "write file %s faild", log_index_file_name.c_str());
        abort();
    }
}

void BinLogger::Truncate(int64_t start_slot_index) {

}

void BinLogger::DumpLogEntry(const LogEntry& log_entry, std::string* buf) {
    assert(buf);
    int32_t total_len = sizeof(uint8_t)
                        + sizeof(int32_t) + log_entry.key.size()
                        + sizeof(int32_t) + log_entry.value.size()
                        + sizeof(int64_t);
    buf->resize(total_len);
    int32_t key_size = log_entry.key.size();
    int32_t value_size = log_entry.value.size();
    char* p = reinterpret_cast<char*>((*buf)[0]);
    p[0] = static_cast<uint8_t>(log_entry.op);
    p += sizeof(uint8_t);
    memcpy(p, static_cast<const void*>(&key_size), sizeof(int32_t));
    p += sizeof(int32_t);
    memcpy(p, static_cast<const void*>(log_entry.key.data()), log_entry.key.size());
    p += log_entry.key.size();
    memcpy(p, static_cast<const void*>(&value_size), sizeof(int32_t));
    p += sizeof(int32_t);
    memcpy(p, static_cast<const void*>(log_entry.value.data()), log_entry.value.size());
    p += log_entry.value.size();
    memcpy(p, static_cast<const void*>(&log_entry.term), sizeof(int64_t));
}

void BinLogger::LoadLogEntry(const std::string& buf, LogEntry* log_entry) {
    assert(log_entry);
    const char* p = buf.data();
    int32_t key_size = 0;
    int32_t value_size = 0;
    memcpy(static_cast<void*>(&log_entry->op), p, sizeof(uint8_t));
    p += sizeof(uint8_t);
    memcpy(static_cast<void*>(&key_size), p, sizeof(int32_t));
    log_entry->key.resize(key_size);
    p += sizeof(int32_t);
    memcpy(static_cast<void*>(&log_entry->key[0]), p, key_size);
    p += key_size;
    memcpy(static_cast<void*>(&value_size), p, sizeof(int32_t));
    log_entry->value.resize(value_size);
    p += sizeof(int32_t);
    memcpy(static_cast<void*>(&log_entry->value[0]), p, value_size);
    p += value_size;
    memcpy(static_cast<void*>(&log_entry->term), p , sizeof(int64_t));
}

} //namespace ins
} //namespace galaxy

<|endoftext|>