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

#include "IDWriteFontCollectionMock.h"
#include "IDWriteTextLayoutMock.h"

using namespace testing;
using namespace System;
using namespace SlimDX;
using namespace SlimDX::DirectWrite;

ref class MockedTextLayout
{
public:
	MockedTextLayout()
		: mockLayout(new IDWriteTextLayoutMock),
		layout(TextLayout::FromPointer(System::IntPtr(mockLayout)))
	{
	}
	~MockedTextLayout()
	{
		delete layout;
		layout = nullptr;
		delete mockLayout;
		mockLayout = 0;
	}
	property IDWriteTextLayoutMock &Mock
	{
		IDWriteTextLayoutMock &get() { return *mockLayout; }
	}
	property TextLayout ^Layout
	{
		TextLayout ^get() { return layout; }
	}

private:
	IDWriteTextLayoutMock *mockLayout;
	TextLayout ^layout;
};

class TextLayoutTest : public testing::Test
{
protected:
	virtual void TearDown()
	{
		ASSERT_EQ(0, ObjectTable::Objects->Count);
	}
};

static DWRITE_CLUSTER_METRICS ExpectedClusterMetrics()
{
	DWRITE_CLUSTER_METRICS expectedMetrics;
	expectedMetrics.width = 15.0f;
	expectedMetrics.length = 1;
	expectedMetrics.canWrapLineAfter = 0;
	expectedMetrics.isWhitespace = 0;
	expectedMetrics.isNewline = 0;
	expectedMetrics.isSoftHyphen = 0;
	expectedMetrics.isRightToLeft = 0;
	return expectedMetrics;
}

static void AssertClusterMetricsMatchExpected(ClusterMetrics metrics)
{
	DWRITE_CLUSTER_METRICS expected = ExpectedClusterMetrics();
	ASSERT_EQ( expected.width, metrics.Width );
	ASSERT_EQ( expected.length, metrics.Length );
	ASSERT_EQ( expected.canWrapLineAfter != 0, metrics.CanWrapLineAfter );
	ASSERT_EQ( expected.isWhitespace != 0, metrics.IsWhitespace );
	ASSERT_EQ( expected.isNewline != 0, metrics.IsNewline );
	ASSERT_EQ( expected.isSoftHyphen != 0, metrics.IsSoftHyphen );
	ASSERT_EQ( expected.isRightToLeft != 0, metrics.IsRightToLeft );
}

TEST_F(TextLayoutTest, GetClusterMetrics)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, GetClusterMetrics(_, _, _))
		.WillRepeatedly(Return(E_UNEXPECTED));
	EXPECT_CALL(layout.Mock, GetClusterMetrics(0, 0, NotNull()))
		.WillOnce(DoAll(SetArgumentPointee<2>(1),
						Return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))));
	EXPECT_CALL(layout.Mock, GetClusterMetrics(NotNull(), Gt(0U), NotNull()))
		.WillOnce(DoAll(SetArgumentPointee<0>(ExpectedClusterMetrics()),
						SetArgumentPointee<2>(1),
						Return(S_OK)));
	array<SlimDX::DirectWrite::ClusterMetrics>^ metrics = layout.Layout->GetClusterMetrics();
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_TRUE( metrics != nullptr );
	ASSERT_EQ( 1, metrics->Length );
	AssertClusterMetricsMatchExpected(metrics[0]);
}

TEST_F(TextLayoutTest, DetermineMinWidth)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, DetermineMinWidth(NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<0>(14.5f), Return(S_OK)));
	float minWidth = -1.0f;
	ASSERT_EQ( 14.5f, layout.Layout->DetermineMinWidth() );
}

static DWRITE_HIT_TEST_METRICS ExpectedHitTestMetrics()
{
	DWRITE_HIT_TEST_METRICS expectedMetrics;
	expectedMetrics.textPosition = 0;
	expectedMetrics.length = 1;
	expectedMetrics.left = 0.15f;
	expectedMetrics.top = 0.245f;
	expectedMetrics.width = 45.8f;
	expectedMetrics.height = 998.5f;
	expectedMetrics.bidiLevel = 23;
	expectedMetrics.isText = TRUE;
	expectedMetrics.isTrimmed = TRUE;
	return expectedMetrics;
}

static void AssertHitTestMetricsMatchExpected(HitTestMetrics% actual)
{
	DWRITE_HIT_TEST_METRICS expected = ExpectedHitTestMetrics();
	ASSERT_EQ( expected.textPosition, actual.TextPosition );
	ASSERT_EQ( expected.length, actual.Length );
	ASSERT_EQ( expected.left, actual.Left );
	ASSERT_EQ( expected.top, actual.Top );
	ASSERT_EQ( expected.width, actual.Width );
	ASSERT_EQ( expected.height, actual.Height );
	ASSERT_EQ( expected.bidiLevel, actual.BidiLevel );
	ASSERT_EQ( expected.isText == TRUE, actual.IsText );
	ASSERT_EQ( expected.isTrimmed == TRUE, actual.IsTrimmed );
}

TEST_F(TextLayoutTest, HitTestPoint)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestPoint(10.0f, 12.0f, NotNull(), NotNull(), NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<2>(false),
						SetArgumentPointee<3>(false),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	bool isTrailingHit = true;
	bool isInside = true;
	HitTestMetrics metrics = layout.Layout->HitTestPoint(10.0f, 12.0f, isTrailingHit, isInside);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_FALSE( isTrailingHit );
	ASSERT_FALSE( isInside );
	AssertHitTestMetricsMatchExpected(metrics);
}

TEST_F(TextLayoutTest, HitTestTextPosition)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestTextPosition(12U, FALSE, NotNull(), NotNull(), NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<2>(12.5f),
						SetArgumentPointee<3>(13.5f),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	float x, y;
	HitTestMetrics metrics = layout.Layout->HitTestTextPosition(12U, false, x, y);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_EQ( 12.5f, x );
	ASSERT_EQ( 13.5f, y );
	AssertHitTestMetricsMatchExpected(metrics);
}

TEST_F(TextLayoutTest, HitTestTextRange)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestTextRange(12U, 4U, 10.0f, 12.0f, 0, 0, NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<6>(1U), Return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))));
	EXPECT_CALL(layout.Mock, HitTestTextRange(12U, 4U, 10.0f, 12.0f, NotNull(), 1U, NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<6>(1U),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	array<HitTestMetrics> ^metrics = layout.Layout->HitTestTextRange(12U, 4U, 10.0f, 12.0f);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_EQ( 1, metrics->Length );
	AssertHitTestMetricsMatchExpected(metrics[0]);
}

TEST_F(TextLayoutTest, GetFontCollectionNoTextRange)
{
	MockedTextLayout layout;
	IDWriteFontCollectionMock mockCollection;
	EXPECT_CALL(layout.Mock, GetFontCollection(0, NotNull(), 0))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<1>(&mockCollection), Return(S_OK)));
	FontCollection ^collection = layout.Layout->GetFontCollection(0);
	ASSERT_TRUE( collection != nullptr );
	ASSERT_EQ( collection->InternalPointer, &mockCollection );
	delete collection;
}
<commit_msg>DirectWrite : Implemented : TextLayout.GetFontCollection returning optional TextRange<commit_after>#include "stdafx.h"
/*
* Copyright (c) 2007-2010 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "IDWriteFontCollectionMock.h"
#include "IDWriteTextLayoutMock.h"

using namespace testing;
using namespace System;
using namespace SlimDX;
using namespace SlimDX::DirectWrite;

ref class MockedTextLayout
{
public:
	MockedTextLayout()
		: mockLayout(new IDWriteTextLayoutMock),
		layout(TextLayout::FromPointer(System::IntPtr(mockLayout)))
	{
	}
	~MockedTextLayout()
	{
		delete layout;
		layout = nullptr;
		delete mockLayout;
		mockLayout = 0;
	}
	property IDWriteTextLayoutMock &Mock
	{
		IDWriteTextLayoutMock &get() { return *mockLayout; }
	}
	property TextLayout ^Layout
	{
		TextLayout ^get() { return layout; }
	}

private:
	IDWriteTextLayoutMock *mockLayout;
	TextLayout ^layout;
};

class TextLayoutTest : public testing::Test
{
protected:
	virtual void TearDown()
	{
		ASSERT_EQ(0, ObjectTable::Objects->Count);
	}
};

static DWRITE_CLUSTER_METRICS ExpectedClusterMetrics()
{
	DWRITE_CLUSTER_METRICS expectedMetrics;
	expectedMetrics.width = 15.0f;
	expectedMetrics.length = 1;
	expectedMetrics.canWrapLineAfter = 0;
	expectedMetrics.isWhitespace = 0;
	expectedMetrics.isNewline = 0;
	expectedMetrics.isSoftHyphen = 0;
	expectedMetrics.isRightToLeft = 0;
	return expectedMetrics;
}

static void AssertClusterMetricsMatchExpected(ClusterMetrics metrics)
{
	DWRITE_CLUSTER_METRICS expected = ExpectedClusterMetrics();
	ASSERT_EQ( expected.width, metrics.Width );
	ASSERT_EQ( expected.length, metrics.Length );
	ASSERT_EQ( expected.canWrapLineAfter != 0, metrics.CanWrapLineAfter );
	ASSERT_EQ( expected.isWhitespace != 0, metrics.IsWhitespace );
	ASSERT_EQ( expected.isNewline != 0, metrics.IsNewline );
	ASSERT_EQ( expected.isSoftHyphen != 0, metrics.IsSoftHyphen );
	ASSERT_EQ( expected.isRightToLeft != 0, metrics.IsRightToLeft );
}

TEST_F(TextLayoutTest, GetClusterMetrics)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, GetClusterMetrics(_, _, _))
		.WillRepeatedly(Return(E_UNEXPECTED));
	EXPECT_CALL(layout.Mock, GetClusterMetrics(0, 0, NotNull()))
		.WillOnce(DoAll(SetArgumentPointee<2>(1),
						Return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))));
	EXPECT_CALL(layout.Mock, GetClusterMetrics(NotNull(), Gt(0U), NotNull()))
		.WillOnce(DoAll(SetArgumentPointee<0>(ExpectedClusterMetrics()),
						SetArgumentPointee<2>(1),
						Return(S_OK)));
	array<SlimDX::DirectWrite::ClusterMetrics>^ metrics = layout.Layout->GetClusterMetrics();
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_TRUE( metrics != nullptr );
	ASSERT_EQ( 1, metrics->Length );
	AssertClusterMetricsMatchExpected(metrics[0]);
}

TEST_F(TextLayoutTest, DetermineMinWidth)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, DetermineMinWidth(NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<0>(14.5f), Return(S_OK)));
	float minWidth = -1.0f;
	ASSERT_EQ( 14.5f, layout.Layout->DetermineMinWidth() );
}

static DWRITE_HIT_TEST_METRICS ExpectedHitTestMetrics()
{
	DWRITE_HIT_TEST_METRICS expectedMetrics;
	expectedMetrics.textPosition = 0;
	expectedMetrics.length = 1;
	expectedMetrics.left = 0.15f;
	expectedMetrics.top = 0.245f;
	expectedMetrics.width = 45.8f;
	expectedMetrics.height = 998.5f;
	expectedMetrics.bidiLevel = 23;
	expectedMetrics.isText = TRUE;
	expectedMetrics.isTrimmed = TRUE;
	return expectedMetrics;
}

static void AssertHitTestMetricsMatchExpected(HitTestMetrics% actual)
{
	DWRITE_HIT_TEST_METRICS expected = ExpectedHitTestMetrics();
	ASSERT_EQ( expected.textPosition, actual.TextPosition );
	ASSERT_EQ( expected.length, actual.Length );
	ASSERT_EQ( expected.left, actual.Left );
	ASSERT_EQ( expected.top, actual.Top );
	ASSERT_EQ( expected.width, actual.Width );
	ASSERT_EQ( expected.height, actual.Height );
	ASSERT_EQ( expected.bidiLevel, actual.BidiLevel );
	ASSERT_EQ( expected.isText == TRUE, actual.IsText );
	ASSERT_EQ( expected.isTrimmed == TRUE, actual.IsTrimmed );
}

TEST_F(TextLayoutTest, HitTestPoint)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestPoint(10.0f, 12.0f, NotNull(), NotNull(), NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<2>(false),
						SetArgumentPointee<3>(false),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	bool isTrailingHit = true;
	bool isInside = true;
	HitTestMetrics metrics = layout.Layout->HitTestPoint(10.0f, 12.0f, isTrailingHit, isInside);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_FALSE( isTrailingHit );
	ASSERT_FALSE( isInside );
	AssertHitTestMetricsMatchExpected(metrics);
}

TEST_F(TextLayoutTest, HitTestTextPosition)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestTextPosition(12U, FALSE, NotNull(), NotNull(), NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<2>(12.5f),
						SetArgumentPointee<3>(13.5f),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	float x, y;
	HitTestMetrics metrics = layout.Layout->HitTestTextPosition(12U, false, x, y);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_EQ( 12.5f, x );
	ASSERT_EQ( 13.5f, y );
	AssertHitTestMetricsMatchExpected(metrics);
}

TEST_F(TextLayoutTest, HitTestTextRange)
{
	MockedTextLayout layout;
	EXPECT_CALL(layout.Mock, HitTestTextRange(12U, 4U, 10.0f, 12.0f, 0, 0, NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<6>(1U), Return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))));
	EXPECT_CALL(layout.Mock, HitTestTextRange(12U, 4U, 10.0f, 12.0f, NotNull(), 1U, NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<6>(1U),
						SetArgumentPointee<4>(ExpectedHitTestMetrics()),
						Return(S_OK)));
	array<HitTestMetrics> ^metrics = layout.Layout->HitTestTextRange(12U, 4U, 10.0f, 12.0f);
	ASSERT_TRUE( Result::Last.IsSuccess );
	ASSERT_EQ( 1, metrics->Length );
	AssertHitTestMetricsMatchExpected(metrics[0]);
}

TEST_F(TextLayoutTest, GetFontCollectionNoTextRange)
{
	MockedTextLayout layout;
	IDWriteFontCollectionMock mockCollection;
	EXPECT_CALL(layout.Mock, GetFontCollection(0, NotNull(), 0))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<1>(&mockCollection), Return(S_OK)));
	FontCollection ^collection = layout.Layout->GetFontCollection(0);
	ASSERT_TRUE( collection != nullptr );
	ASSERT_EQ( collection->InternalPointer, &mockCollection );
	delete collection;
}

TEST_F(TextLayoutTest, GetFontCollectionWithTextRange)
{
	MockedTextLayout layout;
	IDWriteFontCollectionMock mockCollection;
	DWRITE_TEXT_RANGE fakeTextRange;
	fakeTextRange.length = 1;
	fakeTextRange.startPosition = 0;
	EXPECT_CALL(layout.Mock, GetFontCollection(0, NotNull(), NotNull()))
		.Times(1)
		.WillOnce(DoAll(SetArgumentPointee<1>(&mockCollection),
						SetArgumentPointee<2>(fakeTextRange),
						Return(S_OK)));
	TextRange textRange;
	FontCollection ^collection = layout.Layout->GetFontCollection(0, textRange);
	ASSERT_TRUE( collection != nullptr );
	ASSERT_EQ( collection->InternalPointer, &mockCollection );
	ASSERT_EQ( 1, textRange.Length );
	ASSERT_EQ( 0, textRange.StartPosition );
	delete collection;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/private/qquickfontloader_p.h>
#include "../../shared/util.h"
#include "../../shared/testhttpserver.h"
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>

#define SERVER_PORT 14448

class tst_qquickfontloader : public QQmlDataTest
{
    Q_OBJECT
public:
    tst_qquickfontloader();

private slots:
    void initTestCase();
    void noFont();
    void namedFont();
    void localFont();
    void failLocalFont();
    void webFont();
    void redirWebFont();
    void failWebFont();
    void changeFont();
    void changeFontSourceViaState();

private:
    QQmlEngine engine;
    TestHTTPServer server;
};

tst_qquickfontloader::tst_qquickfontloader() :
    server(SERVER_PORT)
{
}

void tst_qquickfontloader::initTestCase()
{
    QQmlDataTest::initTestCase();
    server.serveDirectory(dataDirectory());
    QVERIFY(server.isValid());
}

void tst_qquickfontloader::noFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QCOMPARE(fontObject->name(), QString(""));
    QCOMPARE(fontObject->source(), QUrl(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Null);

    delete fontObject;
}

void tst_qquickfontloader::namedFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { name: \"Helvetica\" }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QCOMPARE(fontObject->source(), QUrl(""));
    QCOMPARE(fontObject->name(), QString("Helvetica"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::localFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" + testFileUrl("tarzeau_ocr_a.ttf").toString() + "\" }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::failLocalFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" + testFileUrl("dummy.ttf").toString() + "\" }";
    QTest::ignoreMessage(QtWarningMsg, QString("file::2:1: QML FontLoader: Cannot load font: \"" + testFileUrl("dummy.ttf").toString() + "\"").toUtf8().constData());
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Error);
}

void tst_qquickfontloader::webFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/tarzeau_ocr_a.ttf\" }";
    QQmlComponent component(&engine);

    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::redirWebFont()
{
    server.addRedirect("olddir/oldname.ttf","../tarzeau_ocr_a.ttf");

    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/olddir/oldname.ttf\" }";
    QQmlComponent component(&engine);

    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::failWebFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/nonexist.ttf\" }";
    QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML FontLoader: Cannot load font: \"http://localhost:14448/nonexist.ttf\"");
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Error);
}

void tst_qquickfontloader::changeFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: font }";
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("font", testFileUrl("tarzeau_ocr_a.ttf"));
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);

    QSignalSpy nameSpy(fontObject, SIGNAL(nameChanged()));
    QSignalSpy statusSpy(fontObject, SIGNAL(statusChanged()));

    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 0);
    QCOMPARE(statusSpy.count(), 0);
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    ctxt->setContextProperty("font", "http://localhost:14448/daniel.ttf");
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Loading);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 1);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("Daniel"));

    ctxt->setContextProperty("font", testFileUrl("tarzeau_ocr_a.ttf"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 2);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    ctxt->setContextProperty("font", "http://localhost:14448/daniel.ttf");
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 3);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("Daniel"));
}

void tst_qquickfontloader::changeFontSourceViaState()
{
    QQuickView canvas(testFileUrl("qtbug-20268.qml"));
    canvas.show();
    canvas.requestActivateWindow();
    QTest::qWaitForWindowShown(&canvas);
    QTRY_COMPARE(&canvas, qGuiApp->focusWindow());

    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(qvariant_cast<QObject *>(canvas.rootObject()->property("fontloader")));
    QVERIFY(fontObject != 0);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    canvas.rootObject()->setProperty("usename", true);

    // This warning should probably not be printed once QTBUG-20268 is fixed
    QString warning = QString(testFileUrl("qtbug-20268.qml").toString()) +
                              QLatin1String(":13:5: QML FontLoader: Cannot load font: \"\"");
    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));

    QEXPECT_FAIL("", "QTBUG-20268", Abort);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(canvas.rootObject()->property("name").toString(), QString("Tahoma"));
}

QTEST_MAIN(tst_qquickfontloader)

#include "tst_qquickfontloader.moc"
<commit_msg>Skip some font loader tests for Windows<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/private/qquickfontloader_p.h>
#include "../../shared/util.h"
#include "../../shared/testhttpserver.h"
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>

#define SERVER_PORT 14448

class tst_qquickfontloader : public QQmlDataTest
{
    Q_OBJECT
public:
    tst_qquickfontloader();

private slots:
    void initTestCase();
    void noFont();
    void namedFont();
    void localFont();
    void failLocalFont();
    void webFont();
    void redirWebFont();
    void failWebFont();
    void changeFont();
    void changeFontSourceViaState();

private:
    QQmlEngine engine;
    TestHTTPServer server;
};

tst_qquickfontloader::tst_qquickfontloader() :
    server(SERVER_PORT)
{
}

void tst_qquickfontloader::initTestCase()
{
    QQmlDataTest::initTestCase();
    server.serveDirectory(dataDirectory());
    QVERIFY(server.isValid());
}

void tst_qquickfontloader::noFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QCOMPARE(fontObject->name(), QString(""));
    QCOMPARE(fontObject->source(), QUrl(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Null);

    delete fontObject;
}

void tst_qquickfontloader::namedFont()
{
    QString componentStr = "import QtQuick 2.0\nFontLoader { name: \"Helvetica\" }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QCOMPARE(fontObject->source(), QUrl(""));
    QCOMPARE(fontObject->name(), QString("Helvetica"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::localFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" + testFileUrl("tarzeau_ocr_a.ttf").toString() + "\" }";
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::failLocalFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" + testFileUrl("dummy.ttf").toString() + "\" }";
    QTest::ignoreMessage(QtWarningMsg, QString("file::2:1: QML FontLoader: Cannot load font: \"" + testFileUrl("dummy.ttf").toString() + "\"").toUtf8().constData());
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Error);
}

void tst_qquickfontloader::webFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/tarzeau_ocr_a.ttf\" }";
    QQmlComponent component(&engine);

    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::redirWebFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    server.addRedirect("olddir/oldname.ttf","../tarzeau_ocr_a.ttf");

    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/olddir/oldname.ttf\" }";
    QQmlComponent component(&engine);

    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
}

void tst_qquickfontloader::failWebFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"http://localhost:14448/nonexist.ttf\" }";
    QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML FontLoader: Cannot load font: \"http://localhost:14448/nonexist.ttf\"");
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString(""));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Error);
}

void tst_qquickfontloader::changeFont()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QString componentStr = "import QtQuick 2.0\nFontLoader { source: font }";
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("font", testFileUrl("tarzeau_ocr_a.ttf"));
    QQmlComponent component(&engine);
    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create());

    QVERIFY(fontObject != 0);

    QSignalSpy nameSpy(fontObject, SIGNAL(nameChanged()));
    QSignalSpy statusSpy(fontObject, SIGNAL(statusChanged()));

    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 0);
    QCOMPARE(statusSpy.count(), 0);
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    ctxt->setContextProperty("font", "http://localhost:14448/daniel.ttf");
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Loading);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 1);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("Daniel"));

    ctxt->setContextProperty("font", testFileUrl("tarzeau_ocr_a.ttf"));
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 2);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    ctxt->setContextProperty("font", "http://localhost:14448/daniel.ttf");
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(nameSpy.count(), 3);
    QCOMPARE(statusSpy.count(), 2);
    QTRY_COMPARE(fontObject->name(), QString("Daniel"));
}

void tst_qquickfontloader::changeFontSourceViaState()
{
#if defined(Q_OS_WIN)
    QSKIP("Windows doesn't support font loading.");
#endif
    QQuickView canvas(testFileUrl("qtbug-20268.qml"));
    canvas.show();
    canvas.requestActivateWindow();
    QTest::qWaitForWindowShown(&canvas);
    QTRY_COMPARE(&canvas, qGuiApp->focusWindow());

    QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(qvariant_cast<QObject *>(canvas.rootObject()->property("fontloader")));
    QVERIFY(fontObject != 0);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QVERIFY(fontObject->source() != QUrl(""));
    QTRY_COMPARE(fontObject->name(), QString("OCRA"));

    canvas.rootObject()->setProperty("usename", true);

    // This warning should probably not be printed once QTBUG-20268 is fixed
    QString warning = QString(testFileUrl("qtbug-20268.qml").toString()) +
                              QLatin1String(":13:5: QML FontLoader: Cannot load font: \"\"");
    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));

    QEXPECT_FAIL("", "QTBUG-20268", Abort);
    QTRY_VERIFY(fontObject->status() == QQuickFontLoader::Ready);
    QCOMPARE(canvas.rootObject()->property("name").toString(), QString("Tahoma"));
}

QTEST_MAIN(tst_qquickfontloader)

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


<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
// Global functions for accessing the model data.
//
// =============================================================================

#include "chrono_vehicle/ChVehicleModelData.h"

namespace chrono {
namespace vehicle {

// -----------------------------------------------------------------------------
// Functions for manipulating the ChronoVehicle data directory
// -----------------------------------------------------------------------------

static std::string model_data_path("../data/");

// Set the path to the ChronoVehicle model data directory (ATTENTION: not thread safe)
void SetDataPath(const std::string& path)
{
  model_data_path = path;
}

// Obtain the current path to the ChronoVehicle model data directory (thread safe)
const std::string& GetDataPath()
{
  return model_data_path;
}

// Obtain the complete path to the specified filename, given relative to the
// ChronoVehicle model data directory (thread safe)
std::string GetDataFile(const std::string& filename)
{
  return model_data_path + filename;
}

} // end namespace vehicle
} // end namespace chrono

<commit_msg>Update the default location for the data folder for unit_VEHICLE<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
// Global functions for accessing the model data.
//
// =============================================================================

#include "chrono_vehicle/ChVehicleModelData.h"

namespace chrono {
namespace vehicle {

// -----------------------------------------------------------------------------
// Functions for manipulating the ChronoVehicle data directory
// -----------------------------------------------------------------------------

static std::string model_data_path("../data/vehicle/");

// Set the path to the ChronoVehicle model data directory (ATTENTION: not thread safe)
void SetDataPath(const std::string& path)
{
  model_data_path = path;
}

// Obtain the current path to the ChronoVehicle model data directory (thread safe)
const std::string& GetDataPath()
{
  return model_data_path;
}

// Obtain the complete path to the specified filename, given relative to the
// ChronoVehicle model data directory (thread safe)
std::string GetDataFile(const std::string& filename)
{
  return model_data_path + filename;
}

} // end namespace vehicle
} // end namespace chrono

<|endoftext|>


<commit_before>/*! \file
 *
 * \brief  checkpointing of a calculation (source)
 */

#include "pulsar/modulemanager/Checkpoint.hpp"
#include "pulsar/modulemanager/CheckpointIO.hpp"
#include "pulsar/modulemanager/ModuleManager.hpp"
#include "pulsar/output/GlobalOutput.hpp"
#include "pulsar/util/Serialization.hpp"
#include "pulsar/parallel/Parallel.hpp"

using namespace pulsar;

namespace {

struct CacheEntryMetadata
{
    std::string cachekey;
    std::string type;
    bphash::HashValue hash;  //!< Hash of original data, NOT serialized data
    size_t size;             //!< Size of serialized data
    unsigned int policy;     //!< Storage policy

    template<typename Archive>
    void serialize(Archive & ar)
    {
        ar(cachekey, type, hash, size, policy);
    }
};

bool is_meta_key(const std::string & s)
{
    if(s.size() <= 6)
        return false; // needs at least one char + "##META"

    std::string last5 = s.substr(s.size()-6, 6);

    if(last5 == "##META")
        return true;
    else
        return false;
}

bool is_cache_key(const std::string & s)
{
    if(s.size() <= 13)
        return false; // Needs at least "CHKPT_CACHE__" + one char

    std::string first13 = s.substr(0, 13);

    if(first13 != "CHKPT_CACHE__")
        return false;
    else
        return true;
}

std::string make_cache_key(const std::string & datakey)
{
    return std::string("CHKPT_CACHE__") + datakey;
}

std::string
split_cache_key(const std::string & key)
{
    if(!is_cache_key(key))
        throw pulsar::PulsarException("Unknown key format: not a cache key",
                               "key", key);

    return key.substr(13); // remove "CHKPT_CACHE__"
}

} // close anonymous namespace

namespace pulsar {

Checkpoint::Checkpoint(const std::shared_ptr<CheckpointIO> & backend_local,
                       const std::shared_ptr<CheckpointIO> & backend_global)
    : backend_local_(backend_local),
      backend_global_(backend_global)
{
    if(backend_local == backend_global)
        throw PulsarException("Local and Global backends are the same! This will lead to problems");
}

std::vector<std::string>
Checkpoint::form_cache_save_list_(const ModuleManager & mm,
                                  CheckpointIO & backend,
                                  std::function<bool(unsigned int)> policy_check)
{
    using pulsar::detail::GenericHolder;
    using pulsar::detail::SerializedGenericData;

    // modulemanager should be locked already!
    // print out some info and get what we should be checkpointing
    print_global_output("Cache entries in the module manager:\n");

    std::vector<std::string> to_save;

    for(const auto & data : mm.cachemap_.cmap_)
    {
        const auto * gb = data.second.value.get();

        bool save = false;
        char stat = ' ';

        // is this actually serialized data?
        const GenericHolder<SerializedGenericData> * sd = dynamic_cast<const GenericHolder<SerializedGenericData> *>(gb);
        bool is_serialized = (sd != nullptr);

        if(policy_check(data.second.policy) && (is_serialized || gb->is_serializable()))
        {
            std::string full_key = make_cache_key(data.first);
            std::string full_metakey = full_key + "##META";

            // does the data already exist in the checkpoint backend?
            if(backend.count(full_key))
            {
                // if it's hashable, read the metadata and compare the hashes
                if(gb->is_hashable())
                {
                    ByteArray ba_meta = backend.read(full_metakey);
                    auto meta = from_byte_array<CacheEntryMetadata>(ba_meta);

                    auto newhash = gb->my_hash();
                    if(newhash != meta.hash)
                    {
                        save = true;
                        stat = 'O';
                    }
                    else
                    {
                        save = false;
                        stat = 'E';
                    }

                }
                else
                {
                    // always err on saving it, even though it may already
                    // be written (we can't hash it, so we don't know!)
                    save = true;
                    stat = '!';
                }
            }
            else
            {
                // doesn't exist on disk yet
                stat = '*';
                save = true;
            }
        }

        print_global_output("        %?  %?\n", stat, data.first);

        if(save)
            to_save.push_back(data.first);
    }

    return to_save;
}

void Checkpoint::save_cache_(const ModuleManager & mm,
                             CheckpointIO & backend,
                             std::function<bool(unsigned int)> policy_check)
{
     // to/from_byte_array

    // Actually save the data
    backend.open();

    // we have to lock the module manager for a while
    std::lock_guard<std::mutex> l_mm(mm.mutex_);

    // print out some info and get what we should be checkpointing
    auto to_save = form_cache_save_list_(mm, backend, policy_check);

    try {

        for(const auto & cachekey : to_save)
        {
            const auto & cdat = mm.cachemap_.cmap_.at(cachekey);
            const auto & gb = *(cdat.value);
            unsigned int policy = cdat.policy;
            const std::string full_key = make_cache_key(cachekey);
            const std::string full_metakey = full_key + "##META";

            // serialize the data
            ByteArray ba_data = gb.to_byte_array();

            bphash::HashValue h;
            if(gb.is_hashable())
                h = gb.my_hash();

            // construct the metadata
            CacheEntryMetadata meta{cachekey,
                                    gb.type(),
                                    h,
                                    ba_data.size(),
                                    policy};
            ByteArray ba_meta = to_byte_array(meta);

            print_global_output("Saving: (%10? bytes)   %?\n", ba_data.size(), cachekey);

            // write to the backend
            backend.write(full_key, ba_data);
            backend.write(full_metakey, ba_meta);
        }
    }
    catch(...)
    {
        backend.close();
        throw;
    }

    backend.close();
}

void Checkpoint::load_cache_(ModuleManager & mm, CheckpointIO & backend)
{
    using namespace pulsar::detail;
     // to/from_byte_array

    // not sure if I really have to lock mm, byt why not
    std::lock_guard<std::mutex> l_mm(mm.mutex_);
    std::lock_guard<std::mutex> c_mm(mm.cachemap_.mutex_);

    backend.open();

    try {
        auto all_keys = backend.all_keys();

        print_global_output("Checkpoint keys:\n");
        for(const auto & key : all_keys)
            print_global_output("    %?\n", key);

        // load the data
        for(const auto & it : all_keys)
        {
            if(is_cache_key(it) && !is_meta_key(it))
            {
                const std::string metakey = it + "##META";

                std::string cachekey = split_cache_key(it);
                print_global_output("Loading %?\n", cachekey);

                ByteArray data = backend.read(it);
                ByteArray metadata = backend.read(metakey);
                auto cem = from_byte_array<CacheEntryMetadata>(metadata);

                SerializedGenericData scd{std::move(data), cem.type, cem.hash, cem.policy};
                std::unique_ptr<GenericHolder<SerializedGenericData>> sdh(new GenericHolder<SerializedGenericData>(std::move(scd)));
                mm.cachemap_.set_(cachekey, std::move(sdh), cem.policy); // set_ won't lock the mutex
            }
        }
    }
    catch(...)
    {
        backend.close();
        throw;
    }

    backend.close();
}

void Checkpoint::perform_on_all_ranks_(const std::string & description, std::function<void(void)> func)
{
    const long my_rank = get_proc_id();
    const long nproc = get_nproc();

    for(long rank = 0; rank < nproc; rank++)
    {
        if(rank == my_rank)
        {
            // perform the action
            print_global_output("On rank %?: ", my_rank);
            print_global_output(description + "\n");
            func(); // call the function
        }

        MPI_Barrier(MPI_COMM_WORLD); //! \todo different comm?
    }
}

void Checkpoint::save_local_cache(const ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    print_global_output("Saving local cache\n");
    save_cache_(mm, *backend_local_,
                    [](unsigned int pol) { return pol & CacheMap::CheckpointLocal; });
}

void Checkpoint::load_local_cache(ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    print_global_output("Loading local cache\n");
    load_cache_(mm, *backend_local_);
}

void Checkpoint::save_global_cache(const ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    std::function<void(void)> func = std::bind(&Checkpoint::save_cache_, this,
                                               std::ref(mm), std::ref(*backend_global_),
                                               [](unsigned int pol) { return pol & CacheMap::CheckpointGlobal; });

    perform_on_all_ranks_("Saving global cache", func);
}

void Checkpoint::load_global_cache(ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    std::function<void(void)> func = std::bind(&Checkpoint::load_cache_, this,
                                               std::ref(mm), std::ref(*backend_global_));

    perform_on_all_ranks_("Loading global cache", func);
}

} // close namespace pulsar

<commit_msg>Moves some of checkpointed output to debug printing<commit_after>/*! \file
 *
 * \brief  checkpointing of a calculation (source)
 */

#include "pulsar/modulemanager/Checkpoint.hpp"
#include "pulsar/modulemanager/CheckpointIO.hpp"
#include "pulsar/modulemanager/ModuleManager.hpp"
#include "pulsar/output/GlobalOutput.hpp"
#include "pulsar/util/Serialization.hpp"
#include "pulsar/parallel/Parallel.hpp"

using namespace pulsar;

namespace {

struct CacheEntryMetadata
{
    std::string cachekey;
    std::string type;
    bphash::HashValue hash;  //!< Hash of original data, NOT serialized data
    size_t size;             //!< Size of serialized data
    unsigned int policy;     //!< Storage policy

    template<typename Archive>
    void serialize(Archive & ar)
    {
        ar(cachekey, type, hash, size, policy);
    }
};

bool is_meta_key(const std::string & s)
{
    if(s.size() <= 6)
        return false; // needs at least one char + "##META"

    std::string last5 = s.substr(s.size()-6, 6);

    if(last5 == "##META")
        return true;
    else
        return false;
}

bool is_cache_key(const std::string & s)
{
    if(s.size() <= 13)
        return false; // Needs at least "CHKPT_CACHE__" + one char

    std::string first13 = s.substr(0, 13);

    if(first13 != "CHKPT_CACHE__")
        return false;
    else
        return true;
}

std::string make_cache_key(const std::string & datakey)
{
    return std::string("CHKPT_CACHE__") + datakey;
}

std::string
split_cache_key(const std::string & key)
{
    if(!is_cache_key(key))
        throw pulsar::PulsarException("Unknown key format: not a cache key",
                               "key", key);

    return key.substr(13); // remove "CHKPT_CACHE__"
}

} // close anonymous namespace

namespace pulsar {

Checkpoint::Checkpoint(const std::shared_ptr<CheckpointIO> & backend_local,
                       const std::shared_ptr<CheckpointIO> & backend_global)
    : backend_local_(backend_local),
      backend_global_(backend_global)
{
    if(backend_local == backend_global)
        throw PulsarException("Local and Global backends are the same! This will lead to problems");
}

std::vector<std::string>
Checkpoint::form_cache_save_list_(const ModuleManager & mm,
                                  CheckpointIO & backend,
                                  std::function<bool(unsigned int)> policy_check)
{
    using pulsar::detail::GenericHolder;
    using pulsar::detail::SerializedGenericData;

    // modulemanager should be locked already!
    // print out some info and get what we should be checkpointing
    print_global_output("Cache entries in the module manager:\n");

    std::vector<std::string> to_save;

    for(const auto & data : mm.cachemap_.cmap_)
    {
        const auto * gb = data.second.value.get();

        bool save = false;
        char stat = ' ';

        // is this actually serialized data?
        const GenericHolder<SerializedGenericData> * sd = dynamic_cast<const GenericHolder<SerializedGenericData> *>(gb);
        bool is_serialized = (sd != nullptr);

        if(policy_check(data.second.policy) && (is_serialized || gb->is_serializable()))
        {
            std::string full_key = make_cache_key(data.first);
            std::string full_metakey = full_key + "##META";

            // does the data already exist in the checkpoint backend?
            if(backend.count(full_key))
            {
                // if it's hashable, read the metadata and compare the hashes
                if(gb->is_hashable())
                {
                    ByteArray ba_meta = backend.read(full_metakey);
                    auto meta = from_byte_array<CacheEntryMetadata>(ba_meta);

                    auto newhash = gb->my_hash();
                    if(newhash != meta.hash)
                    {
                        save = true;
                        stat = 'O';
                    }
                    else
                    {
                        save = false;
                        stat = 'E';
                    }

                }
                else
                {
                    // always err on saving it, even though it may already
                    // be written (we can't hash it, so we don't know!)
                    save = true;
                    stat = '!';
                }
            }
            else
            {
                // doesn't exist on disk yet
                stat = '*';
                save = true;
            }
        }

        print_global_debug("        %?  %?\n", stat, data.first);

        if(save)
            to_save.push_back(data.first);
    }

    return to_save;
}

void Checkpoint::save_cache_(const ModuleManager & mm,
                             CheckpointIO & backend,
                             std::function<bool(unsigned int)> policy_check)
{
     // to/from_byte_array

    // Actually save the data
    backend.open();

    // we have to lock the module manager for a while
    std::lock_guard<std::mutex> l_mm(mm.mutex_);

    // print out some info and get what we should be checkpointing
    auto to_save = form_cache_save_list_(mm, backend, policy_check);

    try {

        for(const auto & cachekey : to_save)
        {
            const auto & cdat = mm.cachemap_.cmap_.at(cachekey);
            const auto & gb = *(cdat.value);
            unsigned int policy = cdat.policy;
            const std::string full_key = make_cache_key(cachekey);
            const std::string full_metakey = full_key + "##META";

            // serialize the data
            ByteArray ba_data = gb.to_byte_array();

            bphash::HashValue h;
            if(gb.is_hashable())
                h = gb.my_hash();

            // construct the metadata
            CacheEntryMetadata meta{cachekey,
                                    gb.type(),
                                    h,
                                    ba_data.size(),
                                    policy};
            ByteArray ba_meta = to_byte_array(meta);

            print_global_debug("Saving: (%10? bytes)   %?\n", ba_data.size(), cachekey);

            // write to the backend
            backend.write(full_key, ba_data);
            backend.write(full_metakey, ba_meta);
        }
    }
    catch(...)
    {
        backend.close();
        throw;
    }

    backend.close();
}

void Checkpoint::load_cache_(ModuleManager & mm, CheckpointIO & backend)
{
    using namespace pulsar::detail;
     // to/from_byte_array

    // not sure if I really have to lock mm, byt why not
    std::lock_guard<std::mutex> l_mm(mm.mutex_);
    std::lock_guard<std::mutex> c_mm(mm.cachemap_.mutex_);

    backend.open();

    try {
        auto all_keys = backend.all_keys();

        print_global_debug("Checkpoint keys:\n");
        for(const auto & key : all_keys)
            print_global_debug("    %?\n", key);

        // load the data
        for(const auto & it : all_keys)
        {
            if(is_cache_key(it) && !is_meta_key(it))
            {
                const std::string metakey = it + "##META";

                std::string cachekey = split_cache_key(it);
                print_global_debug("Loading %?\n", cachekey);

                ByteArray data = backend.read(it);
                ByteArray metadata = backend.read(metakey);
                auto cem = from_byte_array<CacheEntryMetadata>(metadata);

                SerializedGenericData scd{std::move(data), cem.type, cem.hash, cem.policy};
                std::unique_ptr<GenericHolder<SerializedGenericData>> sdh(new GenericHolder<SerializedGenericData>(std::move(scd)));
                mm.cachemap_.set_(cachekey, std::move(sdh), cem.policy); // set_ won't lock the mutex
            }
        }
    }
    catch(...)
    {
        backend.close();
        throw;
    }

    backend.close();
}

void Checkpoint::perform_on_all_ranks_(const std::string & description, std::function<void(void)> func)
{
    const long my_rank = get_proc_id();
    const long nproc = get_nproc();

    for(long rank = 0; rank < nproc; rank++)
    {
        if(rank == my_rank)
        {
            // perform the action
            print_global_output("On rank %?: ", my_rank);
            print_global_output(description + "\n");
            func(); // call the function
        }

        MPI_Barrier(MPI_COMM_WORLD); //! \todo different comm?
    }
}

void Checkpoint::save_local_cache(const ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    print_global_output("Saving local cache\n");
    save_cache_(mm, *backend_local_,
                    [](unsigned int pol) { return pol & CacheMap::CheckpointLocal; });
}

void Checkpoint::load_local_cache(ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    print_global_output("Loading local cache\n");
    load_cache_(mm, *backend_local_);
}

void Checkpoint::save_global_cache(const ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    std::function<void(void)> func = std::bind(&Checkpoint::save_cache_, this,
                                               std::ref(mm), std::ref(*backend_global_),
                                               [](unsigned int pol) { return pol & CacheMap::CheckpointGlobal; });

    perform_on_all_ranks_("Saving global cache", func);
}

void Checkpoint::load_global_cache(ModuleManager & mm)
{
    if(!backend_local_ || !backend_global_)
        throw PulsarException("Nullptr for backend in Checkpoint");

    std::function<void(void)> func = std::bind(&Checkpoint::load_cache_, this,
                                               std::ref(mm), std::ref(*backend_global_));

    perform_on_all_ranks_("Loading global cache", func);
}

} // close namespace pulsar

<|endoftext|>


<commit_before>/*
  Copyright (c) 2014 Noel R. Cower

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom
  the Software is furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USEOR OTHER DEALINGS
  IN THE SOFTWARE.
*/

#include "context.hh"
#include "write_context.hh"
#include "read_context.hh"
#include "error_strings.hh"

s_sz_context::s_sz_context(sz_allocator_t *alloc)
: error(sz_errstr_no_error)
, ctx_alloc(alloc)
, stream(NULL)
, stream_pos(0)
{
  // nop
}

s_sz_context::~s_sz_context()
{
  // nop
}

sz_response_t
s_sz_context::file_error() const
{
  if (sz_stream_eof(stream)) {
    error = sz_errstr_eof;
    return SZ_ERROR_EOF;
  } else {
    if (mode() == SZ_READER) {
      error = sz_errstr_cannot_read;
      return SZ_ERROR_CANNOT_READ;
    } else {
      error = sz_errstr_cannot_write;
      return SZ_ERROR_CANNOT_WRITE;
    }
  }
}

sz_response_t
s_sz_context::set_stream(sz_stream_t *stream)
{
  if (stream == NULL) {
    error = sz_errstr_null_stream;
    return SZ_ERROR_INVALID_STREAM;
  } else if (opened()) {
    error = sz_errstr_open_set_stream;
    return SZ_ERROR_CONTEXT_OPEN;
  }

  this->stream = stream;
  stream_pos = sz_stream_tell(stream);

  return SZ_SUCCESS;
}

sz_response_t
sz_check_context(const sz_context_t *ctx, sz_mode_t mode)
{
  if (NULL == ctx) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  if (mode != ctx->mode()) {
    ctx->error =
      (mode == SZ_READER)
      ? sz_errstr_read_on_write
      : sz_errstr_write_on_read;

    return SZ_ERROR_INVALID_OPERATION;
  }

  return SZ_SUCCESS;
}

SZ_DEF_BEGIN

const char *sz_get_error(sz_context_t *ctx)
{
  return ctx ? ctx->error : NULL;
}

sz_context_t *
sz_new_context(sz_mode_t mode, sz_allocator_t *allocator)
{
  if (!allocator) {
    allocator = sz_default_allocator();
  }

  void *memory = NULL;
  switch (mode) {
  case SZ_READER: {
    memory = sz_malloc(sizeof(sz_read_context_t), allocator);
    new (memory) sz_read_context_t(allocator);
  } break;

  case SZ_WRITER: {
    memory = sz_malloc(sizeof(sz_write_context_t), allocator);
    new (memory) sz_write_context_t(allocator);
  } break;

  default: break;
  }

  return (sz_context_t *)memory;
}

sz_response_t
sz_destroy_context(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  sz_allocator_t *alloc = ctx->ctx_alloc;
  ctx->~sz_context_t();
  sz_free(ctx, alloc);

  return SZ_SUCCESS;
}

sz_response_t
sz_close(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  return ctx->close();
}

sz_response_t
sz_open(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  return ctx->open();
}

SZ_DEF_END
<commit_msg>Fix formatting of sz_get_error decl.<commit_after>/*
  Copyright (c) 2014 Noel R. Cower

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom
  the Software is furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USEOR OTHER DEALINGS
  IN THE SOFTWARE.
*/

#include "context.hh"
#include "write_context.hh"
#include "read_context.hh"
#include "error_strings.hh"

s_sz_context::s_sz_context(sz_allocator_t *alloc)
: error(sz_errstr_no_error)
, ctx_alloc(alloc)
, stream(NULL)
, stream_pos(0)
{
  // nop
}

s_sz_context::~s_sz_context()
{
  // nop
}

sz_response_t
s_sz_context::file_error() const
{
  if (sz_stream_eof(stream)) {
    error = sz_errstr_eof;
    return SZ_ERROR_EOF;
  } else {
    if (mode() == SZ_READER) {
      error = sz_errstr_cannot_read;
      return SZ_ERROR_CANNOT_READ;
    } else {
      error = sz_errstr_cannot_write;
      return SZ_ERROR_CANNOT_WRITE;
    }
  }
}

sz_response_t
s_sz_context::set_stream(sz_stream_t *stream)
{
  if (stream == NULL) {
    error = sz_errstr_null_stream;
    return SZ_ERROR_INVALID_STREAM;
  } else if (opened()) {
    error = sz_errstr_open_set_stream;
    return SZ_ERROR_CONTEXT_OPEN;
  }

  this->stream = stream;
  stream_pos = sz_stream_tell(stream);

  return SZ_SUCCESS;
}

sz_response_t
sz_check_context(const sz_context_t *ctx, sz_mode_t mode)
{
  if (NULL == ctx) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  if (mode != ctx->mode()) {
    ctx->error =
      (mode == SZ_READER)
      ? sz_errstr_read_on_write
      : sz_errstr_write_on_read;

    return SZ_ERROR_INVALID_OPERATION;
  }

  return SZ_SUCCESS;
}

SZ_DEF_BEGIN

const char *
sz_get_error(sz_context_t *ctx)
{
  return ctx ? ctx->error : NULL;
}

sz_context_t *
sz_new_context(sz_mode_t mode, sz_allocator_t *allocator)
{
  if (!allocator) {
    allocator = sz_default_allocator();
  }

  void *memory = NULL;
  switch (mode) {
  case SZ_READER: {
    memory = sz_malloc(sizeof(sz_read_context_t), allocator);
    new (memory) sz_read_context_t(allocator);
  } break;

  case SZ_WRITER: {
    memory = sz_malloc(sizeof(sz_write_context_t), allocator);
    new (memory) sz_write_context_t(allocator);
  } break;

  default: break;
  }

  return (sz_context_t *)memory;
}

sz_response_t
sz_destroy_context(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  sz_allocator_t *alloc = ctx->ctx_alloc;
  ctx->~sz_context_t();
  sz_free(ctx, alloc);

  return SZ_SUCCESS;
}

sz_response_t
sz_close(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  return ctx->close();
}

sz_response_t
sz_open(sz_context_t *ctx)
{
  if (ctx == NULL) {
    return SZ_ERROR_NULL_CONTEXT;
  }

  return ctx->open();
}

SZ_DEF_END
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "absl/base/casts.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/tests/client_library_test_base.h"
#include "tensorflow/compiler/xla/tests/literal_test_util.h"
#include "tensorflow/compiler/xla/tests/test_macros.h"

namespace xla {
namespace {
class ExhaustiveF32ElementwiseOpTest
    : public ClientLibraryTestBase,
      public ::testing::WithParamInterface<std::pair<int64, int64>> {
 protected:
  ErrorSpec error_spec_{0.0001, 0.0001, /*relaxed_nans=*/true};

  template <typename EnqueueOpTy>
  void ExhaustivelyTestF32Op(EnqueueOpTy enqueue_op,
                             float (*evaluate_op)(float),
                             std::pair<int64, int64> known_incorrect_range) {
    int64 begin, end;
    std::tie(begin, end) = GetParam();
    int64 input_size = end - begin;
    LOG(INFO) << "Checking range [" << begin << ", " << end << ")";

    XlaBuilder builder(TestName());

    Literal input_literal =
        LiteralUtil::CreateFromDimensions(F32, {input_size});
    absl::Span<float> input_arr = input_literal.data<float>();
    for (int64 i = begin; i < end; i++) {
      if (i >= known_incorrect_range.first &&
          i < known_incorrect_range.second) {
        // If the operation is known to be buggy on a specific input clamp that
        // input to 0 under the assumption that the op is at least correct on 0.
        input_arr[i - begin] = 0;
      } else {
        input_arr[i - begin] = absl::bit_cast<float, int>(i);
      }
    }

    TF_ASSERT_OK_AND_ASSIGN(std::unique_ptr<GlobalData> input_data,
                            client_->TransferToServer(input_literal));

    auto input = Parameter(&builder, 0, input_literal.shape(), "input");
    enqueue_op(&builder, input);

    std::vector<float> expected_result;
    expected_result.reserve(input_size);
    for (int64 i = 0; i < input_size; i++) {
      expected_result.push_back(evaluate_op(input_arr[i]));
    }

    ComputeAndCompareR1<float>(&builder, expected_result, {input_data.get()},
                               error_spec_);
  }
};

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, LogF32) {
#ifdef XLA_TEST_BACKEND_CPU
  // TODO(b/73141998): The vectorized Log implementation gives results outside
  // our error spec in this range (these numbers are bitwise representations of
  // floats expressed as a zero extended int64).
  std::pair<int64, int64> known_incorrect_range = {1, 8388608};
#else
  std::pair<int64, int64> known_incorrect_range = {0, 0};
#endif

  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Log(input); }, std::log,
      known_incorrect_range);
}

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, ExpF32) {
#ifdef XLA_TEST_BACKEND_CPU
  // TODO(b/73142289): The vectorized Exp implementation gives results outside
  // our error spec in this range (these numbers are bitwise representations of
  // floats expressed as a zero extended int64):
  std::pair<int64, int64> known_incorrect_range = {1107296256 + 11583654,
                                                   1107296256 + 11629080};
#else
  std::pair<int64, int64> known_incorrect_range = {0, 0};
#endif

  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Exp(input); }, std::exp,
      known_incorrect_range);
}

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, TanhF32) {
  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Tanh(input); }, std::tanh,
      /*known_incorrect_range=*/{0, 0});
}

std::vector<std::pair<int64, int64>> CreateExhaustiveParameters() {
  // We break up the 2^32-element space into small'ish chunks to keep peak
  // memory usage low.
  std::vector<std::pair<int64, int64>> result;
  const int64 step = 1 << 25;
  for (int64 i = 0; i < (1l << 32); i += step) {
    result.push_back({i, i + step});
  }
  return result;
}

INSTANTIATE_TEST_CASE_P(ExhaustiveF32ElementwiseOpTestInstance,
                        ExhaustiveF32ElementwiseOpTest,
                        ::testing::ValuesIn(CreateExhaustiveParameters()));
}  // namespace
}  // namespace xla
<commit_msg>[XLA] Use the LocalClient API in exhaustive_f32_elementwise_op_test.<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "absl/base/casts.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/tests/client_library_test_base.h"
#include "tensorflow/compiler/xla/tests/literal_test_util.h"
#include "tensorflow/compiler/xla/tests/test_macros.h"

namespace xla {
namespace {
class ExhaustiveF32ElementwiseOpTest
    : public ClientLibraryTestBase,
      public ::testing::WithParamInterface<std::pair<int64, int64>> {
 protected:
  ErrorSpec error_spec_{0.0001, 0.0001, /*relaxed_nans=*/true};

  template <typename EnqueueOpTy>
  void ExhaustivelyTestF32Op(EnqueueOpTy enqueue_op,
                             float (*evaluate_op)(float),
                             std::pair<int64, int64> known_incorrect_range) {
    int64 begin, end;
    std::tie(begin, end) = GetParam();
    int64 input_size = end - begin;
    LOG(INFO) << "Checking range [" << begin << ", " << end << ")";

    XlaBuilder builder(TestName());

    Literal input_literal =
        LiteralUtil::CreateFromDimensions(F32, {input_size});
    absl::Span<float> input_arr = input_literal.data<float>();
    for (int64 i = begin; i < end; i++) {
      if (i >= known_incorrect_range.first &&
          i < known_incorrect_range.second) {
        // If the operation is known to be buggy on a specific input clamp that
        // input to 0 under the assumption that the op is at least correct on 0.
        input_arr[i - begin] = 0;
      } else {
        input_arr[i - begin] = absl::bit_cast<float, int>(i);
      }
    }

    auto input = Parameter(&builder, 0, input_literal.shape(), "input");
    enqueue_op(&builder, input);
    TF_ASSERT_OK_AND_ASSIGN(XlaComputation comp, builder.Build());

    // Build and run the computation using the LocalClient API, rather than the
    // plain Client API, which is used by ClientLibraryTestBase.  This is
    // because the plain Client API results does more memcpys to/from Literals,
    // and that's slow given that we're touching a lot of data here.
    //
    // Copy debug options from ClientLibraryTestBase.  In particular, we're
    // interested in disabling constant folding.
    ExecutableBuildOptions build_opts;
    *build_opts.mutable_debug_options() = *mutable_debug_options();
    TF_ASSERT_OK_AND_ASSIGN(
        auto executable,
        client_->Compile(comp, {&input_literal.shape()}, build_opts));

    TF_ASSERT_OK_AND_ASSIGN(
        ScopedShapedBuffer input_data,
        client_->LiteralToShapedBuffer(input_literal, /*device_ordinal=*/0));

    ExecutableRunOptions run_opts;
    run_opts.set_allocator(client_->backend().memory_allocator());
    run_opts.set_intra_op_thread_pool(
        client_->backend().eigen_intra_op_thread_pool_device());
    TF_ASSERT_OK_AND_ASSIGN(ScopedShapedBuffer result,
                            executable->Run({&input_data}, run_opts));

    TF_ASSERT_OK_AND_ASSIGN(Literal result_literal,
                            client_->ShapedBufferToLiteral(result));

    Literal expected_literal =
        LiteralUtil::CreateFromDimensions(F32, {input_size});
    absl::Span<float> expected_arr = expected_literal.data<float>();
    for (int64 i = 0; i < input_size; i++) {
      expected_arr[i] = evaluate_op(input_arr[i]);
    }
    EXPECT_TRUE(
        LiteralTestUtil::Near(expected_literal, result_literal, error_spec_));
  }
};

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, LogF32) {
#ifdef XLA_TEST_BACKEND_CPU
  // TODO(b/73141998): The vectorized Log implementation gives results outside
  // our error spec in this range (these numbers are bitwise representations of
  // floats expressed as a zero extended int64).
  std::pair<int64, int64> known_incorrect_range = {1, 8388608};
#else
  std::pair<int64, int64> known_incorrect_range = {0, 0};
#endif

  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Log(input); }, std::log,
      known_incorrect_range);
}

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, ExpF32) {
#ifdef XLA_TEST_BACKEND_CPU
  // TODO(b/73142289): The vectorized Exp implementation gives results outside
  // our error spec in this range (these numbers are bitwise representations of
  // floats expressed as a zero extended int64):
  std::pair<int64, int64> known_incorrect_range = {1107296256 + 11583654,
                                                   1107296256 + 11629080};
#else
  std::pair<int64, int64> known_incorrect_range = {0, 0};
#endif

  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Exp(input); }, std::exp,
      known_incorrect_range);
}

XLA_TEST_P(ExhaustiveF32ElementwiseOpTest, TanhF32) {
  ExhaustivelyTestF32Op(
      [](XlaBuilder* builder, const XlaOp& input) { Tanh(input); }, std::tanh,
      /*known_incorrect_range=*/{0, 0});
}

std::vector<std::pair<int64, int64>> CreateExhaustiveParameters() {
  // We break up the 2^32-element space into small'ish chunks to keep peak
  // memory usage low.
  std::vector<std::pair<int64, int64>> result;
  const int64 step = 1 << 25;
  for (int64 i = 0; i < (1l << 32); i += step) {
    result.push_back({i, i + step});
  }
  return result;
}

INSTANTIATE_TEST_CASE_P(ExhaustiveF32ElementwiseOpTestInstance,
                        ExhaustiveF32ElementwiseOpTest,
                        ::testing::ValuesIn(CreateExhaustiveParameters()));
}  // namespace
}  // namespace xla
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#ifdef GOOGLE_CUDA
#include "tensorflow/stream_executor/cuda/cuda_activation.h"
#include "third_party/gpus/cuda/include/cuda.h"
#include "third_party/gpus/cuda/include/cuda_runtime_api.h"
#endif  // GOOGLE_CUDA

#include "tensorflow/core/common_runtime/gpu/gpu_cudamallocasync_allocator.h"

#include "tensorflow/core/common_runtime/device/device_id_utils.h"
#include "tensorflow/core/common_runtime/gpu/gpu_id.h"
#include "tensorflow/core/common_runtime/gpu/gpu_init.h"
#include "tensorflow/core/framework/allocator.h"
#include "tensorflow/core/platform/stream_executor.h"
#include "tensorflow/core/util/env_var.h"

namespace tensorflow {

GpuCudaMallocAsyncAllocator::GpuCudaMallocAsyncAllocator(
    PlatformGpuId platform_gpu_id, size_t pool_size,
    bool reserve_memory, bool compute_stats)
    : cuda_stream_(nullptr),
      name_(absl::StrCat("gpu_async_", platform_gpu_id.value())) {
  stream_exec_ =
      DeviceIdUtil::ExecutorForPlatformDeviceId(GPUMachineManager(),
                                                platform_gpu_id).ValueOrDie();

#if CUDA_VERSION < 11020
  LOG(FATAL) << "TF_GPU_ALLOCATOR=cuda_malloc_async need CUDA 11.2 or higher to compile.";
#else
  // Initialized here as it only exist if compiled with a recent
  // enough CUDA.
  pool_ = nullptr;
  // WAR an CUDA 11.2 driver bug for multiple-GPU. It currently
  // request that the context on GPU 0 is initialized. Which isn't the
  // case for TF+horovod.
  if (platform_gpu_id.value() > 0) {
    CUcontext pctx; // We loose track of it. But this is fine.
    CUresult err = cuDevicePrimaryCtxRetain(&pctx, 0);
    if (err != CUDA_SUCCESS){
      LOG(FATAL) << "Failed to create the context on device 0.";
    }
  }

  se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
  int cuda_malloc_async_supported;
  cudaDeviceGetAttribute(&cuda_malloc_async_supported,
                         cudaDevAttrMemoryPoolsSupported,
                         platform_gpu_id.value());
  if (!cuda_malloc_async_supported) {
    LOG(FATAL) << "TF_GPU_ALLOCATOR=cuda_malloc_async isn't currently supported."
               << " Possible causes: device not supported, driver too old, "
               << " OS not supported, CUDA version too old.";
  }

  cudaError_t cerr = cudaStreamCreate(&cuda_stream_);
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not allocate CUDA stream for context : "
               << cudaGetErrorString(cerr);
  }

  cerr = cudaDeviceGetDefaultMemPool(&pool_, platform_gpu_id.value());
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not get the default CUDA pool : "
               << cudaGetErrorString(cerr);
  }
  VLOG(1) << Name() << " CudaMallocAsync initialized on platform: "
          << platform_gpu_id.value() << " with pool size of: "
          << pool_size << " this ptr: " << this;
  cerr = cudaMemPoolSetAttribute(pool_, cudaMemPoolAttrReleaseThreshold,
                                 reinterpret_cast<void*>(&pool_size));
  if (compute_stats) {
    stats_.bytes_limit = static_cast<int64>(pool_size);
  } // If not set, it means we do not compute stats.
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not set the default CUDA pool memory threshold : "
               << cudaGetErrorString(cerr);
    pool_ = nullptr;
  }

  // If in TF_DETERMINISTIC_OPS is set, then make the allocator behave
  // determistically.
  bool deterministic_ops = false;
  TF_CHECK_OK(tensorflow::ReadBoolFromEnvVar("TF_DETERMINISTIC_OPS",
                                             /*default_val=*/false,
                                             &deterministic_ops));
  if (deterministic_ops) {
    cudaMemPoolSetAttribute(pool_, cudaMemPoolReuseAllowOpportunistic, 0);
    cudaMemPoolSetAttribute(pool_, cudaMemPoolReuseAllowInternalDependencies, 0);
  }
#endif

  VLOG(2) << Name() << " GpuCudaMallocAsyncAllocator PoolSize " << pool_size;
  if (reserve_memory) {
    void* ptr = AllocateRaw(0, pool_size);
    DeallocateRaw(ptr);
    VLOG(2) << Name() << " GpuCudaMallocAsyncAllocator reserved the pool";
    ClearStats();
  }
}

GpuCudaMallocAsyncAllocator::~GpuCudaMallocAsyncAllocator() {
  cuStreamDestroy(cuda_stream_);
}

void* GpuCudaMallocAsyncAllocator::AllocateRaw(size_t alignment,
                                               size_t num_bytes) {
#if CUDA_VERSION < 11020 || !defined(GOOGLE_CUDA)
  return nullptr;
#else
  if (pool_ == nullptr) {
    LOG(FATAL) << "The instantiation of GpuCudaMallocAsyncAllocator failed."
               << " See previous errors.";
  }
  se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
  void* ptr = 0;
  cudaError_t res = cudaMallocFromPoolAsync(&ptr, num_bytes, pool_, cuda_stream_);
  if (res != cudaSuccess) {
    size_t free, total;
    cudaMemGetInfo(&free, &total);
    LOG(ERROR) << Name() << " cudaMallocAsync failed to allocate " << num_bytes
               << "\n Error name: " << cudaGetErrorName(res)
               << "\n Error sting: " << cudaGetErrorString(res)
               << "\n Free memory/Total memory: " << free << "/" << total
               << "\n Stats: \n" << stats_.DebugString();
    return nullptr;
  }

  // Update stats.
  if (stats_.bytes_limit.has_value()) {
    ++stats_.num_allocs;
    stats_.bytes_in_use += num_bytes;
    stats_.peak_bytes_in_use =
        std::max(stats_.peak_bytes_in_use, stats_.bytes_in_use);
    stats_.largest_alloc_size =
        std::max<std::size_t>(stats_.largest_alloc_size, num_bytes);
    size_map_[ptr] = num_bytes;
  }
  VLOG(10) << Name() << " Allocated " << num_bytes << " at " << ptr;
  return ptr;
#endif
}
void GpuCudaMallocAsyncAllocator::DeallocateRaw(void* ptr) {
#if CUDA_VERSION < 11020 || !defined(GOOGLE_CUDA)
#else
  cudaError_t res = cudaFreeAsync(ptr, cuda_stream_);
  if (res != cudaSuccess) {
    size_t free, total;
    se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
    cudaMemGetInfo(&free, &total);
    LOG(ERROR) << "cudaFreeAsync failed to free " << ptr
               << "\n Error name: " << cudaGetErrorName(res)
               << "\n Error sting: " << cudaGetErrorString(res)
               << "\n Free memory/Total memory: " << free << "/" << total
               << "\n Stats: \n" << stats_.DebugString();
  }

  // Updates the stats.
  if (stats_.bytes_limit.has_value()) {
    DCHECK(size_map_.contains(ptr));
    size_t size = size_map_[ptr];
    stats_.bytes_in_use -= size;
    size_map_.erase(ptr);
  }

  VLOG(10) << Name() << " Freed ptr: " << ptr;
#endif  // GOOGLE_CUDA
}

bool GpuCudaMallocAsyncAllocator::TracksAllocationSizes() const {
  return stats_.bytes_limit.has_value();
}

size_t GpuCudaMallocAsyncAllocator::RequestedSize(const void* ptr) const {
  CHECK(ptr);
  return size_map_.at(ptr);
}

size_t GpuCudaMallocAsyncAllocator::AllocatedSize(const void* ptr) const {
  CHECK(ptr);
  return size_map_.at(ptr);
}

absl::optional<AllocatorStats> GpuCudaMallocAsyncAllocator::GetStats() {
  mutex_lock l(lock_);
  return stats_;
}

void GpuCudaMallocAsyncAllocator::ClearStats() {
  mutex_lock l(lock_);
  stats_.num_allocs = 0;
  stats_.peak_bytes_in_use = stats_.bytes_in_use;
  stats_.largest_alloc_size = 0;
}

}  // namespace tensorflow
<commit_msg>Correctly use the lock.<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#ifdef GOOGLE_CUDA
#include "tensorflow/stream_executor/cuda/cuda_activation.h"
#include "third_party/gpus/cuda/include/cuda.h"
#include "third_party/gpus/cuda/include/cuda_runtime_api.h"
#endif  // GOOGLE_CUDA

#include "tensorflow/core/common_runtime/gpu/gpu_cudamallocasync_allocator.h"

#include "tensorflow/core/common_runtime/device/device_id_utils.h"
#include "tensorflow/core/common_runtime/gpu/gpu_id.h"
#include "tensorflow/core/common_runtime/gpu/gpu_init.h"
#include "tensorflow/core/framework/allocator.h"
#include "tensorflow/core/platform/stream_executor.h"
#include "tensorflow/core/util/env_var.h"

namespace tensorflow {

GpuCudaMallocAsyncAllocator::GpuCudaMallocAsyncAllocator(
    PlatformGpuId platform_gpu_id, size_t pool_size,
    bool reserve_memory, bool compute_stats)
    : cuda_stream_(nullptr),
      name_(absl::StrCat("gpu_async_", platform_gpu_id.value())) {
  stream_exec_ =
      DeviceIdUtil::ExecutorForPlatformDeviceId(GPUMachineManager(),
                                                platform_gpu_id).ValueOrDie();

#if CUDA_VERSION < 11020
  LOG(FATAL) << "TF_GPU_ALLOCATOR=cuda_malloc_async need CUDA 11.2 or higher to compile.";
#else
  // Initialized here as it only exist if compiled with a recent
  // enough CUDA.
  pool_ = nullptr;
  // WAR an CUDA 11.2 driver bug for multiple-GPU. It currently
  // request that the context on GPU 0 is initialized. Which isn't the
  // case for TF+horovod.
  if (platform_gpu_id.value() > 0) {
    CUcontext pctx; // We loose track of it. But this is fine.
    CUresult err = cuDevicePrimaryCtxRetain(&pctx, 0);
    if (err != CUDA_SUCCESS){
      LOG(FATAL) << "Failed to create the context on device 0.";
    }
  }

  se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
  int cuda_malloc_async_supported;
  cudaDeviceGetAttribute(&cuda_malloc_async_supported,
                         cudaDevAttrMemoryPoolsSupported,
                         platform_gpu_id.value());
  if (!cuda_malloc_async_supported) {
    LOG(FATAL) << "TF_GPU_ALLOCATOR=cuda_malloc_async isn't currently supported."
               << " Possible causes: device not supported, driver too old, "
               << " OS not supported, CUDA version too old.";
  }

  cudaError_t cerr = cudaStreamCreate(&cuda_stream_);
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not allocate CUDA stream for context : "
               << cudaGetErrorString(cerr);
  }

  cerr = cudaDeviceGetDefaultMemPool(&pool_, platform_gpu_id.value());
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not get the default CUDA pool : "
               << cudaGetErrorString(cerr);
  }
  VLOG(1) << Name() << " CudaMallocAsync initialized on platform: "
          << platform_gpu_id.value() << " with pool size of: "
          << pool_size << " this ptr: " << this;
  cerr = cudaMemPoolSetAttribute(pool_, cudaMemPoolAttrReleaseThreshold,
                                 reinterpret_cast<void*>(&pool_size));
  if (compute_stats) {
    mutex_lock lock(lock_);
    stats_.bytes_limit = static_cast<int64>(pool_size);
  } // If not set, it means we do not compute stats.
  if (cerr != cudaSuccess) {
    LOG(FATAL) << "could not set the default CUDA pool memory threshold : "
               << cudaGetErrorString(cerr);
    pool_ = nullptr;
  }

  // If in TF_DETERMINISTIC_OPS is set, then make the allocator behave
  // determistically.
  bool deterministic_ops = false;
  TF_CHECK_OK(tensorflow::ReadBoolFromEnvVar("TF_DETERMINISTIC_OPS",
                                             /*default_val=*/false,
                                             &deterministic_ops));
  if (deterministic_ops) {
    cudaMemPoolSetAttribute(pool_, cudaMemPoolReuseAllowOpportunistic, 0);
    cudaMemPoolSetAttribute(pool_, cudaMemPoolReuseAllowInternalDependencies, 0);
  }
#endif

  VLOG(2) << Name() << " GpuCudaMallocAsyncAllocator PoolSize " << pool_size;
  if (reserve_memory) {
    void* ptr = AllocateRaw(0, pool_size);
    DeallocateRaw(ptr);
    VLOG(2) << Name() << " GpuCudaMallocAsyncAllocator reserved the pool";
    ClearStats();
  }
}

GpuCudaMallocAsyncAllocator::~GpuCudaMallocAsyncAllocator() {
  cuStreamDestroy(cuda_stream_);
}

void* GpuCudaMallocAsyncAllocator::AllocateRaw(size_t alignment,
                                               size_t num_bytes) {
#if CUDA_VERSION < 11020 || !defined(GOOGLE_CUDA)
  return nullptr;
#else
  if (pool_ == nullptr) {
    LOG(FATAL) << "The instantiation of GpuCudaMallocAsyncAllocator failed."
               << " See previous errors.";
  }
  se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
  void* ptr = 0;
  cudaError_t res = cudaMallocFromPoolAsync(&ptr, num_bytes, pool_, cuda_stream_);
  if (res != cudaSuccess) {
    size_t free, total;
    cudaMemGetInfo(&free, &total);
    mutex_lock lock(lock_);
    LOG(ERROR) << Name() << " cudaMallocAsync failed to allocate " << num_bytes
               << "\n Error name: " << cudaGetErrorName(res)
               << "\n Error sting: " << cudaGetErrorString(res)
               << "\n Free memory/Total memory: " << free << "/" << total
               << "\n Stats: \n" << stats_.DebugString();
    return nullptr;
  }

  // Update stats.
  if (stats_.bytes_limit.has_value()) {
    mutex_lock lock(lock_);
    ++stats_.num_allocs;
    stats_.bytes_in_use += num_bytes;
    stats_.peak_bytes_in_use =
        std::max(stats_.peak_bytes_in_use, stats_.bytes_in_use);
    stats_.largest_alloc_size =
        std::max<std::size_t>(stats_.largest_alloc_size, num_bytes);
    size_map_[ptr] = num_bytes;
  }
  VLOG(10) << Name() << " Allocated " << num_bytes << " at " << ptr;
  return ptr;
#endif
}
void GpuCudaMallocAsyncAllocator::DeallocateRaw(void* ptr) {
#if CUDA_VERSION < 11020 || !defined(GOOGLE_CUDA)
#else
  cudaError_t res = cudaFreeAsync(ptr, cuda_stream_);
  if (res != cudaSuccess) {
    size_t free, total;
    se::cuda::ScopedActivateExecutorContext scoped_activation{stream_exec_};
    cudaMemGetInfo(&free, &total);
    LOG(ERROR) << "cudaFreeAsync failed to free " << ptr
               << "\n Error name: " << cudaGetErrorName(res)
               << "\n Error sting: " << cudaGetErrorString(res)
               << "\n Free memory/Total memory: " << free << "/" << total
               << "\n Stats: \n" << stats_.DebugString();
  }

  // Updates the stats.
  if (stats_.bytes_limit.has_value()) {
    mutex_lock lock(lock_);
    DCHECK(size_map_.contains(ptr));
    size_t size = size_map_[ptr];
    stats_.bytes_in_use -= size;
    size_map_.erase(ptr);
  }

  VLOG(10) << Name() << " Freed ptr: " << ptr;
#endif  // GOOGLE_CUDA
}

bool GpuCudaMallocAsyncAllocator::TracksAllocationSizes() const {
  return stats_.bytes_limit.has_value();
}

size_t GpuCudaMallocAsyncAllocator::RequestedSize(const void* ptr) const {
  CHECK(ptr);
  return size_map_.at(ptr);
}

size_t GpuCudaMallocAsyncAllocator::AllocatedSize(const void* ptr) const {
  CHECK(ptr);
  return size_map_.at(ptr);
}

absl::optional<AllocatorStats> GpuCudaMallocAsyncAllocator::GetStats() {
  mutex_lock l(lock_);
  return stats_;
}

void GpuCudaMallocAsyncAllocator::ClearStats() {
  mutex_lock l(lock_);
  stats_.num_allocs = 0;
  stats_.peak_bytes_in_use = stats_.bytes_in_use;
  stats_.largest_alloc_size = 0;
}

}  // namespace tensorflow
<|endoftext|>