<commit_before>#include <cstdlib>
#include <string>
#include <string.h>
#include <vips/vips.h>

#include "common.h"

// Verify platform and compiler compatibility

#if (VIPS_MAJOR_VERSION < 7 || (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 40))
#error libvips version 7.40.0+ required - see http://sharp.dimens.io/page/install
#endif

#ifdef _WIN64
#error Windows 64-bit is currently unsupported - see http://sharp.dimens.io/page/install#windows
#endif

#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
#error GCC version 4.6+ is required for C++11 features - see http://sharp.dimens.io/page/install#prerequisites
#endif

#if (defined(__clang__) && defined(__has_feature))
#if (!__has_feature(cxx_range_for))
#error clang version 3.0+ is required for C++11 features - see http://sharp.dimens.io/page/install#prerequisites
#endif
#endif

#define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"

namespace sharp {

  // How many tasks are in the queue?
  volatile int counterQueue = 0;

  // How many tasks are being processed?
  volatile int counterProcess = 0;

  // Filename extension checkers
  static bool EndsWith(std::string const &str, std::string const &end) {
    return str.length() >= end.length() && 0 == str.compare(str.length() - end.length(), end.length(), end);
  }
  bool IsJpeg(std::string const &str) {
    return EndsWith(str, ".jpg") || EndsWith(str, ".jpeg") || EndsWith(str, ".JPG") || EndsWith(str, ".JPEG");
  }
  bool IsPng(std::string const &str) {
    return EndsWith(str, ".png") || EndsWith(str, ".PNG");
  }
  bool IsWebp(std::string const &str) {
    return EndsWith(str, ".webp") || EndsWith(str, ".WEBP");
  }
  bool IsTiff(std::string const &str) {
    return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
  }
  bool IsDz(std::string const &str) {
    return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
  }

  /*
    Determine image format of a buffer.
  */
  ImageType DetermineImageType(void *buffer, size_t const length) {
    ImageType imageType = ImageType::UNKNOWN;
    char const *load = vips_foreign_find_load_buffer(buffer, length);
    if (load != NULL) {
      std::string loader = load;
      if (EndsWith(loader, "JpegBuffer")) {
        imageType = ImageType::JPEG;
      } else if (EndsWith(loader, "PngBuffer")) {
        imageType = ImageType::PNG;
      } else if (EndsWith(loader, "WebpBuffer")) {
        imageType = ImageType::WEBP;
      } else if (EndsWith(loader, "TiffBuffer")) {
        imageType = ImageType::TIFF;
      } else if (EndsWith(loader, "MagickBuffer")) {
        imageType = ImageType::MAGICK;
      }
    }
    return imageType;
  }

  /*
    Initialise and return a VipsImage from a buffer. Supports JPEG, PNG, WebP and TIFF.
  */
  VipsImage* InitImage(void *buffer, size_t const length, VipsAccess const access) {
    return vips_image_new_from_buffer(buffer, length, NULL, "access", access, NULL);
  }

  /*
    Determine image format, reads the first few bytes of the file
  */
  ImageType DetermineImageType(char const *file) {
    ImageType imageType = ImageType::UNKNOWN;
    char const *load = vips_foreign_find_load(file);
    if (load != NULL) {
      std::string loader = load;
      if (EndsWith(loader, "JpegFile")) {
        imageType = ImageType::JPEG;
      } else if (EndsWith(loader, "Png")) {
        imageType = ImageType::PNG;
      } else if (EndsWith(loader, "WebpFile")) {
        imageType = ImageType::WEBP;
      } else if (EndsWith(loader, "Openslide")) {
        imageType = ImageType::OPENSLIDE;
      } else if (EndsWith(loader, "TiffFile")) {
        imageType = ImageType::TIFF;
      } else if (EndsWith(loader, "Magick") || EndsWith(loader, "MagickFile")) {
        imageType = ImageType::MAGICK;
      }
    }
    return imageType;
  }

  /*
    Initialise and return a VipsImage from a file.
  */
  VipsImage* InitImage(char const *file, VipsAccess const access) {
    return vips_image_new_from_file(file, "access", access, NULL);
  }

  /*
    Does this image have an embedded profile?
  */
  bool HasProfile(VipsImage *image) {
    return (vips_image_get_typeof(image, VIPS_META_ICC_NAME) > 0) ? TRUE : FALSE;
  }

  /*
    Does this image have an alpha channel?
    Uses colour space interpretation with number of channels to guess this.
  */
  bool HasAlpha(VipsImage *image) {
    return (
      (image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
      (image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
      (image->Bands == 5 && image->Type == VIPS_INTERPRETATION_CMYK)
    );
  }

  /*
    Get EXIF Orientation of image, if any.
  */
  int ExifOrientation(VipsImage const *image) {
    int orientation = 0;
    const char *exif;
    if (
      vips_image_get_typeof(image, EXIF_IFD0_ORIENTATION) != 0 &&
      !vips_image_get_string(image, EXIF_IFD0_ORIENTATION, &exif)
    ) {
      orientation = atoi(&exif[0]);
    }
    return orientation;
  }

  /*
    Set EXIF Orientation of image.
  */
  void SetExifOrientation(VipsImage *image, int const orientation) {
    char exif[3];
    g_snprintf(exif, sizeof(exif), "%d", orientation);
    vips_image_set_string(image, EXIF_IFD0_ORIENTATION, exif);
  }

  /*
    Remove EXIF Orientation from image.
  */
  void RemoveExifOrientation(VipsImage *image) {
    vips_image_remove(image, EXIF_IFD0_ORIENTATION);
  }

  /*
    Returns the window size for the named interpolator. For example,
    a window size of 3 means a 3x3 pixel grid is used for the calculation.
  */
  int InterpolatorWindowSize(char const *name) {
    VipsInterpolate *interpolator = vips_interpolate_new(name);
    if (interpolator == NULL) {
      return -1;
    }
    int window_size = vips_interpolate_get_window_size(interpolator);
    g_object_unref(interpolator);
    return window_size;
  }

} // namespace sharp
<commit_msg>Support EXIF Orientation removal in libvips v8.1.0<commit_after>#include <cstdlib>
#include <string>
#include <string.h>
#include <vips/vips.h>

#include "common.h"

// Verify platform and compiler compatibility

#if (VIPS_MAJOR_VERSION < 7 || (VIPS_MAJOR_VERSION == 7 && VIPS_MINOR_VERSION < 40))
#error libvips version 7.40.0+ required - see http://sharp.dimens.io/page/install
#endif

#ifdef _WIN64
#error Windows 64-bit is currently unsupported - see http://sharp.dimens.io/page/install#windows
#endif

#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
#error GCC version 4.6+ is required for C++11 features - see http://sharp.dimens.io/page/install#prerequisites
#endif

#if (defined(__clang__) && defined(__has_feature))
#if (!__has_feature(cxx_range_for))
#error clang version 3.0+ is required for C++11 features - see http://sharp.dimens.io/page/install#prerequisites
#endif
#endif

#define EXIF_IFD0_ORIENTATION "exif-ifd0-Orientation"

namespace sharp {

  // How many tasks are in the queue?
  volatile int counterQueue = 0;

  // How many tasks are being processed?
  volatile int counterProcess = 0;

  // Filename extension checkers
  static bool EndsWith(std::string const &str, std::string const &end) {
    return str.length() >= end.length() && 0 == str.compare(str.length() - end.length(), end.length(), end);
  }
  bool IsJpeg(std::string const &str) {
    return EndsWith(str, ".jpg") || EndsWith(str, ".jpeg") || EndsWith(str, ".JPG") || EndsWith(str, ".JPEG");
  }
  bool IsPng(std::string const &str) {
    return EndsWith(str, ".png") || EndsWith(str, ".PNG");
  }
  bool IsWebp(std::string const &str) {
    return EndsWith(str, ".webp") || EndsWith(str, ".WEBP");
  }
  bool IsTiff(std::string const &str) {
    return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
  }
  bool IsDz(std::string const &str) {
    return EndsWith(str, ".dzi") || EndsWith(str, ".DZI");
  }

  /*
    Determine image format of a buffer.
  */
  ImageType DetermineImageType(void *buffer, size_t const length) {
    ImageType imageType = ImageType::UNKNOWN;
    char const *load = vips_foreign_find_load_buffer(buffer, length);
    if (load != NULL) {
      std::string loader = load;
      if (EndsWith(loader, "JpegBuffer")) {
        imageType = ImageType::JPEG;
      } else if (EndsWith(loader, "PngBuffer")) {
        imageType = ImageType::PNG;
      } else if (EndsWith(loader, "WebpBuffer")) {
        imageType = ImageType::WEBP;
      } else if (EndsWith(loader, "TiffBuffer")) {
        imageType = ImageType::TIFF;
      } else if (EndsWith(loader, "MagickBuffer")) {
        imageType = ImageType::MAGICK;
      }
    }
    return imageType;
  }

  /*
    Initialise and return a VipsImage from a buffer. Supports JPEG, PNG, WebP and TIFF.
  */
  VipsImage* InitImage(void *buffer, size_t const length, VipsAccess const access) {
    return vips_image_new_from_buffer(buffer, length, NULL, "access", access, NULL);
  }

  /*
    Determine image format, reads the first few bytes of the file
  */
  ImageType DetermineImageType(char const *file) {
    ImageType imageType = ImageType::UNKNOWN;
    char const *load = vips_foreign_find_load(file);
    if (load != NULL) {
      std::string loader = load;
      if (EndsWith(loader, "JpegFile")) {
        imageType = ImageType::JPEG;
      } else if (EndsWith(loader, "Png")) {
        imageType = ImageType::PNG;
      } else if (EndsWith(loader, "WebpFile")) {
        imageType = ImageType::WEBP;
      } else if (EndsWith(loader, "Openslide")) {
        imageType = ImageType::OPENSLIDE;
      } else if (EndsWith(loader, "TiffFile")) {
        imageType = ImageType::TIFF;
      } else if (EndsWith(loader, "Magick") || EndsWith(loader, "MagickFile")) {
        imageType = ImageType::MAGICK;
      }
    }
    return imageType;
  }

  /*
    Initialise and return a VipsImage from a file.
  */
  VipsImage* InitImage(char const *file, VipsAccess const access) {
    return vips_image_new_from_file(file, "access", access, NULL);
  }

  /*
    Does this image have an embedded profile?
  */
  bool HasProfile(VipsImage *image) {
    return (vips_image_get_typeof(image, VIPS_META_ICC_NAME) > 0) ? TRUE : FALSE;
  }

  /*
    Does this image have an alpha channel?
    Uses colour space interpretation with number of channels to guess this.
  */
  bool HasAlpha(VipsImage *image) {
    return (
      (image->Bands == 2 && image->Type == VIPS_INTERPRETATION_B_W) ||
      (image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) ||
      (image->Bands == 5 && image->Type == VIPS_INTERPRETATION_CMYK)
    );
  }

  /*
    Get EXIF Orientation of image, if any.
  */
  int ExifOrientation(VipsImage const *image) {
    int orientation = 0;
    const char *exif;
    if (
      vips_image_get_typeof(image, EXIF_IFD0_ORIENTATION) != 0 &&
      !vips_image_get_string(image, EXIF_IFD0_ORIENTATION, &exif)
    ) {
      orientation = atoi(&exif[0]);
    }
    return orientation;
  }

  /*
    Set EXIF Orientation of image.
  */
  void SetExifOrientation(VipsImage *image, int const orientation) {
    char exif[3];
    g_snprintf(exif, sizeof(exif), "%d", orientation);
    vips_image_set_string(image, EXIF_IFD0_ORIENTATION, exif);
  }

  /*
    Remove EXIF Orientation from image.
  */
  void RemoveExifOrientation(VipsImage *image) {
    SetExifOrientation(image, 0);
  }

  /*
    Returns the window size for the named interpolator. For example,
    a window size of 3 means a 3x3 pixel grid is used for the calculation.
  */
  int InterpolatorWindowSize(char const *name) {
    VipsInterpolate *interpolator = vips_interpolate_new(name);
    if (interpolator == NULL) {
      return -1;
    }
    int window_size = vips_interpolate_get_window_size(interpolator);
    g_object_unref(interpolator);
    return window_size;
  }

} // namespace sharp
<|endoftext|>


<commit_before>/*

Copyright (c) 2014 Jarryd Beck

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 <iostream>

#include "cxxopts.hpp"

int main(int argc, char* argv[])
{
  try
  {

    cxxopts::Options options;

    options.add_options()
      ("a,apple", "an apple")
      ("b,bob", "Bob")
      ("f,file", "File", cxxopts::value<std::vector<std::string>>())
      ("positional",
        "Positional arguments: these are the arguments that are entered "
        "without an option", cxxopts::value<std::string>())
      ("long-description",
        "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace")
      ("help", "Print help")
      ("int", "An integer", cxxopts::value<int>())
    ;

    options.parse_positional("positional");

    options.parse(argc, argv);

    if (options.count("a"))
    {
      std::cout << "Saw option ‘a’" << std::endl;
    }

    if (options.count("b"))
    {
      std::cout << "Saw option ‘b’" << std::endl;
    }

    if (options.count("f"))
    {
      auto& ff = options["f"].as<std::vector<std::string>>();
      std::cout << "Files" << std::endl;
      for (const auto& f : ff)
      {
        std::cout << f << std::endl;
      }
    }

    if (options.count("help"))
    {
      std::cout << options.help() << std::endl;
    }

    if (options.count("positional"))
    {
      std::cout << "Positional = " << options["positional"].as<std::string>()
        << std::endl;
    }

    if (options.count("int"))
    {
      std::cout << "int = " << options["int"].as<int>() << std::endl;
    }

    std::cout << "Arguments remain = " << argc << std::endl;

  } catch (const cxxopts::OptionException& e)
  {
    std::cout << "error parsing options: " << e.what() << std::endl;
    exit(1);
  }

  return 0;
}
<commit_msg>test long option names<commit_after>/*

Copyright (c) 2014 Jarryd Beck

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 <iostream>

#include "cxxopts.hpp"

int main(int argc, char* argv[])
{
  try
  {

    cxxopts::Options options;

    options.add_options()
      ("a,apple", "an apple")
      ("b,bob", "Bob")
      ("f,file", "File", cxxopts::value<std::vector<std::string>>())
      ("positional",
        "Positional arguments: these are the arguments that are entered "
        "without an option", cxxopts::value<std::string>())
      ("long-description",
        "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace")
      ("help", "Print help")
      ("int", "An integer", cxxopts::value<int>())
      ("option_that_is_too_long_for_the_help", "A very long option")
    ;

    options.parse_positional("positional");

    options.parse(argc, argv);

    if (options.count("a"))
    {
      std::cout << "Saw option ‘a’" << std::endl;
    }

    if (options.count("b"))
    {
      std::cout << "Saw option ‘b’" << std::endl;
    }

    if (options.count("f"))
    {
      auto& ff = options["f"].as<std::vector<std::string>>();
      std::cout << "Files" << std::endl;
      for (const auto& f : ff)
      {
        std::cout << f << std::endl;
      }
    }

    if (options.count("help"))
    {
      std::cout << options.help() << std::endl;
    }

    if (options.count("positional"))
    {
      std::cout << "Positional = " << options["positional"].as<std::string>()
        << std::endl;
    }

    if (options.count("int"))
    {
      std::cout << "int = " << options["int"].as<int>() << std::endl;
    }

    std::cout << "Arguments remain = " << argc << std::endl;

  } catch (const cxxopts::OptionException& e)
  {
    std::cout << "error parsing options: " << e.what() << std::endl;
    exit(1);
  }

  return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;
        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage()));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    QSize size = rootNodeInstance().boundingRect().size().toSize();
    size.scale(100, 100, Qt::KeepAspectRatio);

    QImage image(size, QImage::Format_ARGB32);

    return image;
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner.NodeInstances: Preview images for Qml2<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "qt5previewnodeinstanceserver.h"

#include "nodeinstanceclientinterface.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h"

namespace QmlDesigner {

Qt5PreviewNodeInstanceServer::Qt5PreviewNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
}

void Qt5PreviewNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    initializeView(command.imports());
    setupScene(command);

    startRenderTimer();
}
void Qt5PreviewNodeInstanceServer::startRenderTimer()
{
    if (timerId() != 0)
        killTimer(timerId());

    int timerId = startTimer(renderTimerInterval());

    setTimerId(timerId);
}

void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;

    if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
        inFunction = true;
        QVector<ImageContainer> imageContainerVector;
        imageContainerVector.append(ImageContainer(0, renderPreviewImage()));

        foreach (ServerNodeInstance instance,  rootNodeInstance().stateInstances()) {
            instance.activateState();
            imageContainerVector.append(ImageContainer(instance.instanceId(), renderPreviewImage()));
            instance.deactivateState();
        }

        nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector));

        slowDownRenderTimer();
        inFunction = false;
    }
}

void Qt5PreviewNodeInstanceServer::changeState(const ChangeStateCommand &/*command*/)
{

}

static void updateDirtyNodeRecursive(QSGItem *parentItem)
{
    foreach (QSGItem *childItem, parentItem->childItems())
        updateDirtyNodeRecursive(childItem);

    DesignerSupport::updateDirtyNode(parentItem);
}

QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
{
    updateDirtyNodeRecursive(rootNodeInstance().internalSGItem());

    QRectF boundingRect = rootNodeInstance().boundingRect();

    QSize previewImageSize = boundingRect.size().toSize();
    previewImageSize.scale(QSize(100, 100), Qt::KeepAspectRatio);

    QImage previewImage;

    if (boundingRect.isValid() && rootNodeInstance().internalSGItem())
        previewImage = designerSupport()->renderImageForItem(rootNodeInstance().internalSGItem(), boundingRect, previewImageSize);

    previewImage = previewImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);

    return previewImage;
}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_sync_module.h"

#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
#include "webrtc/video_engine/stream_synchronization.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/voice_engine/include/voe_video_sync.h"

namespace webrtc {

enum { kSyncInterval = 1000};

int UpdateMeasurements(StreamSynchronization::Measurements* stream,
                       const RtpRtcp* rtp_rtcp) {
  stream->latest_timestamp = rtp_rtcp->RemoteTimestamp();
  stream->latest_receive_time_ms = rtp_rtcp->LocalTimeOfRemoteTimeStamp();
  synchronization::RtcpMeasurement measurement;
  if (0 != rtp_rtcp->RemoteNTP(&measurement.ntp_secs,
                               &measurement.ntp_frac,
                               NULL,
                               NULL,
                               &measurement.rtp_timestamp)) {
    return -1;
  }
  if (measurement.ntp_secs == 0 && measurement.ntp_frac == 0) {
    return -1;
  }
  for (synchronization::RtcpList::iterator it = stream->rtcp.begin();
       it != stream->rtcp.end(); ++it) {
    if (measurement.ntp_secs == (*it).ntp_secs &&
        measurement.ntp_frac == (*it).ntp_frac) {
      // This RTCP has already been added to the list.
      return 0;
    }
  }
  // We need two RTCP SR reports to map between RTP and NTP. More than two will
  // not improve the mapping.
  if (stream->rtcp.size() == 2) {
    stream->rtcp.pop_back();
  }
  stream->rtcp.push_front(measurement);
  return 0;
}

ViESyncModule::ViESyncModule(VideoCodingModule* vcm,
                             ViEChannel* vie_channel)
    : data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
      vcm_(vcm),
      vie_channel_(vie_channel),
      video_rtp_rtcp_(NULL),
      voe_channel_id_(-1),
      voe_sync_interface_(NULL),
      last_sync_time_(TickTime::Now()),
      sync_() {
}

ViESyncModule::~ViESyncModule() {
}

int ViESyncModule::ConfigureSync(int voe_channel_id,
                                 VoEVideoSync* voe_sync_interface,
                                 RtpRtcp* video_rtcp_module) {
  CriticalSectionScoped cs(data_cs_.get());
  voe_channel_id_ = voe_channel_id;
  voe_sync_interface_ = voe_sync_interface;
  video_rtp_rtcp_ = video_rtcp_module;
  sync_.reset(new StreamSynchronization(voe_channel_id, vie_channel_->Id()));

  if (!voe_sync_interface) {
    voe_channel_id_ = -1;
    if (voe_channel_id >= 0) {
      // Trying to set a voice channel but no interface exist.
      return -1;
    }
    return 0;
  }
  return 0;
}

int ViESyncModule::VoiceChannel() {
  return voe_channel_id_;
}

int32_t ViESyncModule::TimeUntilNextProcess() {
  return static_cast<int32_t>(kSyncInterval -
      (TickTime::Now() - last_sync_time_).Milliseconds());
}

int32_t ViESyncModule::Process() {
  CriticalSectionScoped cs(data_cs_.get());
  last_sync_time_ = TickTime::Now();

  const int current_video_delay_ms = vcm_->Delay();
  WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
               "Video delay (JB + decoder) is %d ms", current_video_delay_ms);

  if (voe_channel_id_ == -1) {
    return 0;
  }
  assert(video_rtp_rtcp_ && voe_sync_interface_);
  assert(sync_.get());

  int audio_jitter_buffer_delay_ms = 0;
  int playout_buffer_delay_ms = 0;
  if (voe_sync_interface_->GetDelayEstimate(voe_channel_id_,
                                            &audio_jitter_buffer_delay_ms,
                                            &playout_buffer_delay_ms) != 0) {
    // Could not get VoE delay value, probably not a valid channel Id or
    // the channel have not received enough packets.
    WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, vie_channel_->Id(),
                 "%s: VE_GetDelayEstimate error for voice_channel %d",
                 __FUNCTION__, voe_channel_id_);
    return 0;
  }
  const int current_audio_delay_ms = audio_jitter_buffer_delay_ms +
      playout_buffer_delay_ms;

  RtpRtcp* voice_rtp_rtcp = NULL;
  if (0 != voe_sync_interface_->GetRtpRtcp(voe_channel_id_, voice_rtp_rtcp)) {
    return 0;
  }
  assert(voice_rtp_rtcp);

  if (UpdateMeasurements(&video_measurement_, video_rtp_rtcp_) != 0) {
    return 0;
  }

  if (UpdateMeasurements(&audio_measurement_, voice_rtp_rtcp) != 0) {
    return 0;
  }

  int relative_delay_ms;
  // Calculate how much later or earlier the audio stream is compared to video.
  if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
                                   &relative_delay_ms)) {
    return 0;
  }

  TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay", current_video_delay_ms);
  TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay", current_audio_delay_ms);
  TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
  int target_audio_delay_ms = 0;
  int target_video_delay_ms = 0;
  // Calculate the necessary extra audio delay and desired total video
  // delay to get the streams in sync.
  if (!sync_->ComputeDelays(relative_delay_ms,
                            current_audio_delay_ms,
                            &target_audio_delay_ms,
                            &target_video_delay_ms)) {
    return 0;
  }

  WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
               "Set delay current(a=%d v=%d rel=%d) target(a=%d v=%d)",
               current_audio_delay_ms, current_video_delay_ms,
               relative_delay_ms,
               target_audio_delay_ms, target_video_delay_ms);
  if (voe_sync_interface_->SetMinimumPlayoutDelay(
      voe_channel_id_, target_audio_delay_ms) == -1) {
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, vie_channel_->Id(),
                 "Error setting voice delay");
  }
  vcm_->SetMinimumPlayoutDelay(target_video_delay_ms);
  return 0;
}

int ViESyncModule::SetTargetBufferingDelay(int target_delay_ms) {
  CriticalSectionScoped cs(data_cs_.get());
 if (!voe_sync_interface_) {
    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
                 "voe_sync_interface_ NULL, can't set playout delay.");
    return -1;
  }
  sync_->SetTargetBufferingDelay(target_delay_ms);
  // Setting initial playout delay to voice engine (video engine is updated via
  // the VCM interface).
  voe_sync_interface_->SetInitialPlayoutDelay(voe_channel_id_,
                                              target_delay_ms);
  return 0;
}

}  // namespace webrtc
<commit_msg>Fix AV sync issue<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/video_engine/vie_sync_module.h"

#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
#include "webrtc/video_engine/stream_synchronization.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/voice_engine/include/voe_video_sync.h"

namespace webrtc {

enum { kSyncInterval = 1000};

int UpdateMeasurements(StreamSynchronization::Measurements* stream,
                       const RtpRtcp* rtp_rtcp) {
  stream->latest_timestamp = rtp_rtcp->RemoteTimestamp();
  stream->latest_receive_time_ms = rtp_rtcp->LocalTimeOfRemoteTimeStamp();
  synchronization::RtcpMeasurement measurement;
  if (0 != rtp_rtcp->RemoteNTP(&measurement.ntp_secs,
                               &measurement.ntp_frac,
                               NULL,
                               NULL,
                               &measurement.rtp_timestamp)) {
    return -1;
  }
  if (measurement.ntp_secs == 0 && measurement.ntp_frac == 0) {
    return -1;
  }
  for (synchronization::RtcpList::iterator it = stream->rtcp.begin();
       it != stream->rtcp.end(); ++it) {
    if (measurement.ntp_secs == (*it).ntp_secs &&
        measurement.ntp_frac == (*it).ntp_frac) {
      // This RTCP has already been added to the list.
      return 0;
    }
  }
  // We need two RTCP SR reports to map between RTP and NTP. More than two will
  // not improve the mapping.
  if (stream->rtcp.size() == 2) {
    stream->rtcp.pop_back();
  }
  stream->rtcp.push_front(measurement);
  return 0;
}

ViESyncModule::ViESyncModule(VideoCodingModule* vcm,
                             ViEChannel* vie_channel)
    : data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
      vcm_(vcm),
      vie_channel_(vie_channel),
      video_rtp_rtcp_(NULL),
      voe_channel_id_(-1),
      voe_sync_interface_(NULL),
      last_sync_time_(TickTime::Now()),
      sync_() {
}

ViESyncModule::~ViESyncModule() {
}

int ViESyncModule::ConfigureSync(int voe_channel_id,
                                 VoEVideoSync* voe_sync_interface,
                                 RtpRtcp* video_rtcp_module) {
  CriticalSectionScoped cs(data_cs_.get());
  voe_channel_id_ = voe_channel_id;
  voe_sync_interface_ = voe_sync_interface;
  video_rtp_rtcp_ = video_rtcp_module;
  sync_.reset(new StreamSynchronization(voe_channel_id, vie_channel_->Id()));

  if (!voe_sync_interface) {
    voe_channel_id_ = -1;
    if (voe_channel_id >= 0) {
      // Trying to set a voice channel but no interface exist.
      return -1;
    }
    return 0;
  }
  return 0;
}

int ViESyncModule::VoiceChannel() {
  return voe_channel_id_;
}

int32_t ViESyncModule::TimeUntilNextProcess() {
  return static_cast<int32_t>(kSyncInterval -
      (TickTime::Now() - last_sync_time_).Milliseconds());
}

int32_t ViESyncModule::Process() {
  CriticalSectionScoped cs(data_cs_.get());
  last_sync_time_ = TickTime::Now();

  const int current_video_delay_ms = vcm_->Delay();
  WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
               "Video delay (JB + decoder) is %d ms", current_video_delay_ms);

  if (voe_channel_id_ == -1) {
    return 0;
  }
  assert(video_rtp_rtcp_ && voe_sync_interface_);
  assert(sync_.get());

  int audio_jitter_buffer_delay_ms = 0;
  int playout_buffer_delay_ms = 0;
  if (voe_sync_interface_->GetDelayEstimate(voe_channel_id_,
                                            &audio_jitter_buffer_delay_ms,
                                            &playout_buffer_delay_ms) != 0) {
    // Could not get VoE delay value, probably not a valid channel Id or
    // the channel have not received enough packets.
    WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideo, vie_channel_->Id(),
                 "%s: VE_GetDelayEstimate error for voice_channel %d",
                 __FUNCTION__, voe_channel_id_);
    return 0;
  }
  const int current_audio_delay_ms = audio_jitter_buffer_delay_ms +
      playout_buffer_delay_ms;

  RtpRtcp* voice_rtp_rtcp = NULL;
  if (0 != voe_sync_interface_->GetRtpRtcp(voe_channel_id_, voice_rtp_rtcp)) {
    return 0;
  }
  assert(voice_rtp_rtcp);

  if (UpdateMeasurements(&video_measurement_, video_rtp_rtcp_) != 0) {
    return 0;
  }

  if (UpdateMeasurements(&audio_measurement_, voice_rtp_rtcp) != 0) {
    return 0;
  }

  int relative_delay_ms;
  // Calculate how much later or earlier the audio stream is compared to video.
  if (!sync_->ComputeRelativeDelay(audio_measurement_, video_measurement_,
                                   &relative_delay_ms)) {
    return 0;
  }

  TRACE_COUNTER1("webrtc", "SyncCurrentVideoDelay", current_video_delay_ms);
  TRACE_COUNTER1("webrtc", "SyncCurrentAudioDelay", current_audio_delay_ms);
  TRACE_COUNTER1("webrtc", "SyncRelativeDelay", relative_delay_ms);
  int target_audio_delay_ms = 0;
  int target_video_delay_ms = current_video_delay_ms;
  // Calculate the necessary extra audio delay and desired total video
  // delay to get the streams in sync.
  if (!sync_->ComputeDelays(relative_delay_ms,
                            current_audio_delay_ms,
                            &target_audio_delay_ms,
                            &target_video_delay_ms)) {
    return 0;
  }

  WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
               "Set delay current(a=%d v=%d rel=%d) target(a=%d v=%d)",
               current_audio_delay_ms, current_video_delay_ms,
               relative_delay_ms,
               target_audio_delay_ms, target_video_delay_ms);
  if (voe_sync_interface_->SetMinimumPlayoutDelay(
      voe_channel_id_, target_audio_delay_ms) == -1) {
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, vie_channel_->Id(),
                 "Error setting voice delay");
  }
  vcm_->SetMinimumPlayoutDelay(target_video_delay_ms);
  return 0;
}

int ViESyncModule::SetTargetBufferingDelay(int target_delay_ms) {
  CriticalSectionScoped cs(data_cs_.get());
 if (!voe_sync_interface_) {
    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, vie_channel_->Id(),
                 "voe_sync_interface_ NULL, can't set playout delay.");
    return -1;
  }
  sync_->SetTargetBufferingDelay(target_delay_ms);
  // Setting initial playout delay to voice engine (video engine is updated via
  // the VCM interface).
  voe_sync_interface_->SetInitialPlayoutDelay(voe_channel_id_,
                                              target_delay_ms);
  return 0;
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/* Copyright 2017 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.
==============================================================================*/

// Usage: capture_tpu_profile --service_addr="localhost:8466" --logdir=/tmp/log
//
// Initiates a TPU profiling on the TPUProfiler service at service_addr,
// receives and dumps the profile data to a tensorboard log directory.

#include "grpc++/grpc++.h"

#include <cstdio>
#include <ctime>
#include <vector>

#include "tensorflow/contrib/tpu/profiler/dump_tpu_profile.h"
#include "tensorflow/contrib/tpu/profiler/tpu_profiler.grpc.pb.h"
#include "tensorflow/contrib/tpu/profiler/version.h"
#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace tensorflow {
namespace tpu {
namespace {

using ::tensorflow::TPUProfiler;

constexpr uint64 kMaxEvents = 1000000;

string GetCurrentTimeStampAsString() {
  char s[128];
  std::time_t t = std::time(nullptr);
  CHECK_NE(std::strftime(s, sizeof(s), "%F_%T", std::localtime(&t)), 0);
  return s;
}

ProfileResponse Profile(const string& service_addr, int duration_ms,
                        const ProfileOptions& opts) {
  ProfileRequest request;
  request.set_duration_ms(duration_ms);
  request.set_max_events(kMaxEvents);
  request.add_tools("input_pipeline");
  request.add_tools("overview_page");
  *request.mutable_opts() = opts;
  std::cout << "Limiting the number of trace events to " << kMaxEvents
            << std::endl;
  ::grpc::ClientContext context;
  ::grpc::ChannelArguments channel_args;
  // TODO(ioeric): use `SetMaxReceiveMessageSize` instead once it's available.
  channel_args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH,
                      std::numeric_limits<int32>::max());
  std::unique_ptr<TPUProfiler::Stub> stub =
      TPUProfiler::NewStub(::grpc::CreateCustomChannel(
          service_addr, ::grpc::InsecureChannelCredentials(), channel_args));
  ProfileResponse response;
  TF_QCHECK_OK(FromGrpcStatus(stub->Profile(&context, request, &response)));
  return response;
}

}  // namespace
}  // namespace tpu
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::string FLAGS_service_addr;
  tensorflow::string FLAGS_logdir;
  int FLAGS_duration_ms = 2000;
  int FLAGS_num_tracing_attempts = 3;
  bool FLAGS_include_dataset_ops = true;
  std::vector<tensorflow::Flag> flag_list = {
      tensorflow::Flag("service_addr", &FLAGS_service_addr,
                       "Address of TPU profiler service e.g. localhost:8466"),
      tensorflow::Flag("logdir", &FLAGS_logdir,
                       "Path of TensorBoard log directory e.g. /tmp/tb_log, "
                       "gs://tb_bucket"),
      tensorflow::Flag("duration_ms", &FLAGS_duration_ms,
                       "Duration of tracing in ms. Default is 2000ms."),
      tensorflow::Flag("num_tracing_attempts", &FLAGS_num_tracing_attempts,
                       "Automatically retry N times when no trace event "
                       "is collected. Default is 3."),
      tensorflow::Flag("include_dataset_ops", &FLAGS_include_dataset_ops,
                       "Set to false to profile longer TPU device traces."),
  };

  std::cout << "Welcome to the Cloud TPU Profiler v" << TPU_PROFILER_VERSION
            << std::endl;

  tensorflow::string usage = tensorflow::Flags::Usage(argv[0], flag_list);
  bool parse_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  if (!parse_ok || FLAGS_service_addr.empty() || FLAGS_logdir.empty()) {
    std::printf("%s", usage.c_str());
    return 2;
  }
  tensorflow::port::InitMain(argv[0], &argc, &argv);

  // Sets the minimum duration_ms and tracing attempts to one.
  int duration_ms = std::max(FLAGS_duration_ms, 1);
  int remaining_attempts = std::max(FLAGS_num_tracing_attempts, 1);
  tensorflow::ProfileOptions opts;
  opts.set_include_dataset_ops(FLAGS_include_dataset_ops);
  tensorflow::ProfileResponse response;

  while (true) {
    std::cout << "Starting to profile TPU traces for " << duration_ms << " ms. "
              << "Remaining attempt(s): " << remaining_attempts-- << std::endl;
    response = tensorflow::tpu::Profile(FLAGS_service_addr, duration_ms, opts);
    if (remaining_attempts <= 0 || !response.encoded_trace().empty()) break;
    std::cout << "No trace event is collected. Automatically retrying."
              << std::endl
              << std::endl;
  }

  if (response.encoded_trace().empty()) {
    std::cout << "No trace event is collected after "
              << FLAGS_num_tracing_attempts << " attempt(s). "
              << "Perhaps, you want to try again (with more attempts?)."
              << std::endl
              << "Tip: increase number of attempts with --num_tracing_attempts."
              << std::endl;
  }

  // Use the current timestamp as the run name.
  tensorflow::string run = tensorflow::tpu::GetCurrentTimeStampAsString();
  TF_CHECK_OK(tensorflow::tpu::WriteTensorboardTPUProfile(
      FLAGS_logdir, run, response, &std::cout));
  // Print this at the end so that it's not buried in irrelevant LOG messages.
  std::cout
      << "NOTE: using the trace duration " << duration_ms << "ms." << std::endl
      << "Set an appropriate duration (with --duration_ms) if you "
         "don't see a full step in your trace or the captured trace is too "
         "large."
      << std::endl;
}
<commit_msg>internal change<commit_after>/* Copyright 2017 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.
==============================================================================*/

// Usage: capture_tpu_profile --service_addr="localhost:8466" --logdir=/tmp/log
//
// Initiates a TPU profiling on the TPUProfiler service at service_addr,
// receives and dumps the profile data to a tensorboard log directory.

#include "grpc++/grpc++.h"

#include <cstdio>
#include <ctime>
#include <vector>

#include "tensorflow/contrib/tpu/profiler/dump_tpu_profile.h"
#include "tensorflow/contrib/tpu/profiler/tpu_profiler.grpc.pb.h"
#include "tensorflow/contrib/tpu/profiler/version.h"
#include "tensorflow/core/distributed_runtime/rpc/grpc_util.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace tensorflow {
namespace tpu {
namespace {

using ::tensorflow::TPUProfiler;

constexpr uint64 kMaxEvents = 1000000;

string GetCurrentTimeStampAsString() {
  char s[128];
  std::time_t t = std::time(nullptr);
  CHECK_NE(std::strftime(s, sizeof(s), "%F_%T", std::localtime(&t)), 0);
  return s;
}

Status ValidateHostPortPair(const string& host_port) {
  uint32 port;
  std::vector<string> parts = str_util::Split(host_port, ':');
  // Must be host:port, port must be a number, host must not contain a '/',
  // host also must not be empty.
  if (parts.size() != 2 || !strings::safe_strtou32(parts[1], &port) ||
      parts[0].find("/") != string::npos || parts[0].empty()) {
    return errors::InvalidArgument("Could not interpret \"", host_port,
                                   "\" as a host-port pair.");
  }
  return Status::OK();
}

ProfileResponse Profile(const string& service_addr, int duration_ms,
                        const ProfileOptions& opts) {
  ProfileRequest request;
  request.set_duration_ms(duration_ms);
  request.set_max_events(kMaxEvents);
  request.add_tools("input_pipeline");
  request.add_tools("overview_page");
  *request.mutable_opts() = opts;
  std::cout << "Limiting the number of trace events to " << kMaxEvents
            << std::endl;
  ::grpc::ClientContext context;
  ::grpc::ChannelArguments channel_args;
  // TODO(ioeric): use `SetMaxReceiveMessageSize` instead once it's available.
  // TODO(qiuminxu): use `NewHostPortGrpcChannel` instead once their
  // `ValidateHostPortPair` checks for empty host string case.
  channel_args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH,
                      std::numeric_limits<int32>::max());
  std::unique_ptr<TPUProfiler::Stub> stub =
      TPUProfiler::NewStub(::grpc::CreateCustomChannel(
          "dns:///" + service_addr, ::grpc::InsecureChannelCredentials(),
          channel_args));
  ProfileResponse response;
  TF_QCHECK_OK(FromGrpcStatus(stub->Profile(&context, request, &response)));
  return response;
}

}  // namespace
}  // namespace tpu
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::string FLAGS_service_addr;
  tensorflow::string FLAGS_logdir;
  int FLAGS_duration_ms = 2000;
  int FLAGS_num_tracing_attempts = 3;
  bool FLAGS_include_dataset_ops = true;
  std::vector<tensorflow::Flag> flag_list = {
      tensorflow::Flag("service_addr", &FLAGS_service_addr,
                       "Address of TPU profiler service e.g. localhost:8466"),
      tensorflow::Flag("logdir", &FLAGS_logdir,
                       "Path of TensorBoard log directory e.g. /tmp/tb_log, "
                       "gs://tb_bucket"),
      tensorflow::Flag("duration_ms", &FLAGS_duration_ms,
                       "Duration of tracing in ms. Default is 2000ms."),
      tensorflow::Flag("num_tracing_attempts", &FLAGS_num_tracing_attempts,
                       "Automatically retry N times when no trace event "
                       "is collected. Default is 3."),
      tensorflow::Flag("include_dataset_ops", &FLAGS_include_dataset_ops,
                       "Set to false to profile longer TPU device traces."),
  };

  std::cout << "Welcome to the Cloud TPU Profiler v" << TPU_PROFILER_VERSION
            << std::endl;

  tensorflow::string usage = tensorflow::Flags::Usage(argv[0], flag_list);
  bool parse_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  if (!parse_ok || FLAGS_service_addr.empty() || FLAGS_logdir.empty()) {
    std::cout << usage.c_str() << std::endl;
    return 2;
  }
  tensorflow::Status status =
      tensorflow::tpu::ValidateHostPortPair(FLAGS_service_addr);
  if (!status.ok()) {
    std::cout << status.error_message() << std::endl;
    std::cout << usage.c_str() << std::endl;
    return 2;
  }
  tensorflow::port::InitMain(argv[0], &argc, &argv);

  // Sets the minimum duration_ms and tracing attempts to one.
  int duration_ms = std::max(FLAGS_duration_ms, 1);
  int remaining_attempts = std::max(FLAGS_num_tracing_attempts, 1);
  tensorflow::ProfileOptions opts;
  opts.set_include_dataset_ops(FLAGS_include_dataset_ops);
  tensorflow::ProfileResponse response;

  while (true) {
    std::cout << "Starting to profile TPU traces for " << duration_ms << " ms. "
              << "Remaining attempt(s): " << remaining_attempts-- << std::endl;
    response = tensorflow::tpu::Profile(FLAGS_service_addr, duration_ms, opts);
    if (remaining_attempts <= 0 || !response.encoded_trace().empty()) break;
    std::cout << "No trace event is collected. Automatically retrying."
              << std::endl
              << std::endl;
  }

  if (response.encoded_trace().empty()) {
    std::cout << "No trace event is collected after "
              << FLAGS_num_tracing_attempts << " attempt(s). "
              << "Perhaps, you want to try again (with more attempts?)."
              << std::endl
              << "Tip: increase number of attempts with --num_tracing_attempts."
              << std::endl;
  }

  // Use the current timestamp as the run name.
  tensorflow::string run = tensorflow::tpu::GetCurrentTimeStampAsString();
  TF_CHECK_OK(tensorflow::tpu::WriteTensorboardTPUProfile(
      FLAGS_logdir, run, response, &std::cout));
  // Print this at the end so that it's not buried in irrelevant LOG messages.
  std::cout
      << "NOTE: using the trace duration " << duration_ms << "ms." << std::endl
      << "Set an appropriate duration (with --duration_ms) if you "
         "don't see a full step in your trace or the captured trace is too "
         "large."
      << std::endl;
}
<|endoftext|>


<commit_before>/* Copyright 2019 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 "tensorflow/lite/delegates/gpu/cl/kernels/softmax1x1.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetSoftmaxKernelCode(
    const OperationDef& op_def,
    const std::vector<ElementwiseOperation*>& linked_operations) {
  TensorCodeGenerator src_tensor("src_data",
                                 WHSBPoint{"tensor_size.x", "tensor_size.y",
                                           "tensor_size.z", "tensor_size.w"},
                                 op_def.src_tensors[0]);
  TensorCodeGenerator dst_tensor("dst_data",
                                 WHSBPoint{"tensor_size.x", "tensor_size.y",
                                           "tensor_size.z", "tensor_size.w"},
                                 op_def.dst_tensors[0]);

  const std::string batch_id = op_def.IsBatchSupported() ? "batch_id" : "";
  std::string c = GetCommonDefines(op_def.precision);
  c += "__kernel void main_function(\n";
  c += src_tensor.GetDeclaration(AccessType::READ);
  c += GetArgsDeclaration(linked_operations);
  c += dst_tensor.GetDeclaration(AccessType::WRITE) + ",\n";
  c += "    int4 tensor_size,\n";
  c += "    int2 size,\n";
  c += "    float4 mask\n";
  c += ") {\n";
  if (op_def.IsBatchSupported()) {
    c += "  int batch_id = get_global_id(1);\n";
    c += "  if (batch_id >= tensor_size.w) return;\n";
  }
  c += "  int offset = 0;\n";
  c += "  float sum = 0.0f;\n";
  c += "  int s = 0;\n";
  c += "  int tid = get_local_id(0);\n";
  c += "  do {\n";
  c += "    int z = offset + tid;\n";
  c += "    if (z < size.x) {\n";
  c += "      float4 mask_temp = z == size.x - 1 ? mask : (float4)(1.0f);\n";
  c += "      float4 src = " +
       src_tensor.ReadAsFloatWHSB("0", "0", "z", batch_id) + ";\n";
  c += "      sum += dot(mask_temp, exp(src));\n";
  c += "      offset += 32;\n";
  c += "    }\n";
  c += "    s++;\n";
  c += "  } while (s < size.y);\n";
  c += "\n";
  c += "  __local float4 tmp[8];\n";
  c += "  __local float* tmpx1 = (__local float*)tmp;\n";
  c += "  tmpx1[tid] = sum;\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  c += "  if (tid == 0) {\n";
  c += "    sum = dot((float4)(1.0f), tmp[0]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[1]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[2]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[3]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[4]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[5]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[6]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[7]);\n";
  c += "    tmpx1[0] = 1.0f / sum;\n";
  c += "  }\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  c += "  sum = tmpx1[0];\n";
  c += "\n";
  c += "  offset = 0;\n";
  c += "  s = 0;\n";
  c += "  do {\n";
  c += "    int z = offset + tid;\n";
  c += "    if (z < size.x) {\n";
  c += "      FLT4 res = TO_FLT4(exp(" +
       src_tensor.ReadAsFloatWHSB("0", "0", "z", batch_id) + ")*sum);\n";
  const LinkingContext context{"res", "0", "0", "z"};
  c += PostProcess(linked_operations, context);
  c += "    " + dst_tensor.WriteWHSB("res", "0", "0", "z", batch_id);
  c += "      offset += 32;\n";
  c += "    }\n";
  c += "    s++;\n";
  c += "  } while (s < size.y);\n";
  c += "}\n";
  return c;
}
}  // namespace

Softmax1x1::Softmax1x1(Softmax1x1&& kernel)
    : GPUOperation(std::move(kernel)), kernel_(std::move(kernel.kernel_)) {}

Softmax1x1& Softmax1x1::operator=(Softmax1x1&& kernel) {
  if (this != &kernel) {
    kernel_ = std::move(kernel.kernel_);
    GPUOperation::operator=(std::move(kernel));
  }
  return *this;
}

absl::Status Softmax1x1::Compile(const CreationContext& creation_context) {
  const auto code = GetSoftmaxKernelCode(definition_, linked_operations_);
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status Softmax1x1::AddToQueue(CLCommandQueue* queue) {
  kernel_.ResetBindingCounter();
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(src_[0]->GetMemoryPtr()));
  RETURN_IF_ERROR(BindArgs(&kernel_, linked_operations_));
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(dst_[0]->GetMemoryPtrForWriting()));
  RETURN_IF_ERROR(kernel_.SetBytesAuto(src_[0]->GetWHSB()));
  const int depth = src_[0]->Slices();
  RETURN_IF_ERROR(kernel_.SetBytesAuto(int2(depth, DivideRoundUp(depth, 32))));
  RETURN_IF_ERROR(
      kernel_.SetBytesAuto(GetMaskForLastPlane(src_[0]->Channels())));

  return queue->DispatchImplicit(kernel_, {32, dst_[0]->Batch(), 1},
                                 {32, 1, 1});
}

Softmax1x1 CreateSoftmax1x1(const OperationDef& definition) {
  return Softmax1x1(definition);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Softmax1x1 converted to new style.<commit_after>/* Copyright 2019 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 "tensorflow/lite/delegates/gpu/cl/kernels/softmax1x1.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetSoftmaxKernelCode(const OperationDef& op_def, Arguments* args) {
  args->AddObjectRef(
      "src_tensor", AccessType::READ,
      absl::make_unique<TensorDescriptor>(op_def.src_tensors[0]));
  args->AddObjectRef(
      "dst_tensor", AccessType::WRITE,
      absl::make_unique<TensorDescriptor>(op_def.dst_tensors[0]));
  args->AddFloat("mask_x");
  args->AddFloat("mask_y");
  args->AddFloat("mask_z");
  args->AddFloat("mask_w");
  args->AddInt("slices_x32");

  std::string c = GetCommonDefines(op_def.precision);
  c += "__kernel void main_function(\n";
  c += "$0) {\n";
  if (op_def.IsBatchSupported()) {
    c += "  int batch_id = get_global_id(1);\n";
    c += "  if (batch_id >= args.dst_tensor.Batch()) return;\n";
    c += "  args.dst_tensor.SetBatchRef(batch_id);\n";
    c += "  args.src_tensor.SetBatchRef(batch_id);\n";
  }
  c += "  float4 mask = (float4)(args.mask_x, args.mask_y, args.mask_z, "
       "args.mask_w);\n";
  c += "  int offset = 0;\n";
  c += "  float sum = 0.0f;\n";
  c += "  int s = 0;\n";
  c += "  int tid = get_local_id(0);\n";
  c += "  do {\n";
  c += "    int z = offset + tid;\n";
  c += "    if (z < args.dst_tensor.Slices()) {\n";
  c += "      float4 mask_temp = z == args.dst_tensor.Slices() - 1 ? mask : "
       "(float4)(1.0f);\n";
  c += "      float4 src = args.src_tensor.Read<float>(0, 0, z);\n";
  c += "      sum += dot(mask_temp, exp(src));\n";
  c += "      offset += 32;\n";
  c += "    }\n";
  c += "    s++;\n";
  c += "  } while (s < args.slices_x32);\n";
  c += "\n";
  c += "  __local float4 tmp[8];\n";
  c += "  __local float* tmpx1 = (__local float*)tmp;\n";
  c += "  tmpx1[tid] = sum;\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  c += "  if (tid == 0) {\n";
  c += "    sum = dot((float4)(1.0f), tmp[0]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[1]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[2]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[3]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[4]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[5]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[6]);\n";
  c += "    sum += dot((float4)(1.0f), tmp[7]);\n";
  c += "    tmpx1[0] = 1.0f / sum;\n";
  c += "  }\n";
  c += "  barrier(CLK_LOCAL_MEM_FENCE);\n";
  c += "  sum = tmpx1[0];\n";
  c += "\n";
  c += "  offset = 0;\n";
  c += "  s = 0;\n";
  c += "  do {\n";
  c += "    int z = offset + tid;\n";
  c += "    if (z < args.dst_tensor.Slices()) {\n";
  c += "      FLT4 res = TO_FLT4(exp(args.src_tensor.Read<float>(0, 0, "
       "z))*sum);\n";
  c += "      args.dst_tensor.Write(res, 0, 0, z);\n";
  c += "      offset += 32;\n";
  c += "    }\n";
  c += "    s++;\n";
  c += "  } while (s < args.slices_x32);\n";
  c += "}\n";
  return c;
}
}  // namespace

Softmax1x1::Softmax1x1(Softmax1x1&& kernel)
    : GPUOperation(std::move(kernel)), kernel_(std::move(kernel.kernel_)) {}

Softmax1x1& Softmax1x1::operator=(Softmax1x1&& kernel) {
  if (this != &kernel) {
    kernel_ = std::move(kernel.kernel_);
    GPUOperation::operator=(std::move(kernel));
  }
  return *this;
}

absl::Status Softmax1x1::Compile(const CreationContext& creation_context) {
  std::string code = GetSoftmaxKernelCode(definition_, &args_);
  std::string element_wise_code;
  RETURN_IF_ERROR(
      MergeOperations(linked_operations_, &args_, &element_wise_code));
  RETURN_IF_ERROR(args_.TransformToCLCode(creation_context.device->GetInfo(),
                                          {{"dst_tensor", element_wise_code}},
                                          &code));
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status Softmax1x1::AddToQueue(CLCommandQueue* queue) {
  RETURN_IF_ERROR(args_.SetObjectRef("src_tensor", src_[0]));
  RETURN_IF_ERROR(args_.SetObjectRef("dst_tensor", dst_[0]));
  float4 mask = GetMaskForLastPlane(src_[0]->Channels());
  RETURN_IF_ERROR(args_.SetFloat("mask_x", mask.x));
  RETURN_IF_ERROR(args_.SetFloat("mask_y", mask.y));
  RETURN_IF_ERROR(args_.SetFloat("mask_z", mask.z));
  RETURN_IF_ERROR(args_.SetFloat("mask_w", mask.w));
  RETURN_IF_ERROR(
      args_.SetInt("slices_x32", DivideRoundUp(src_[0]->Slices(), 32)));
  RETURN_IF_ERROR(SetArguments(linked_operations_, &args_));
  RETURN_IF_ERROR(args_.Bind(kernel_.kernel()));
  return queue->DispatchImplicit(kernel_, {32, dst_[0]->Batch(), 1},
                                 {32, 1, 1});
}

Softmax1x1 CreateSoftmax1x1(const OperationDef& definition) {
  return Softmax1x1(definition);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>#include "base/logging.hpp"

#include "indexer/feature.hpp"

#include "editor/changeset_wrapper.hpp"

#include "std/algorithm.hpp"
#include "std/sstream.hpp"
#include "std/map.hpp"

#include "geometry/mercator.hpp"

#include "private.h"

using editor::XMLFeature;

namespace
{
double ScoreLatLon(XMLFeature const & xmlFt, ms::LatLon const & latLon)
{
  double constexpr eps = MercatorBounds::GetCellID2PointAbsEpsilon();
  // TODO: Find proper score values;
  return latLon.EqualDxDy(xmlFt.GetCenter(), eps) ? 10 ? -10;
}

double ScoreNames(XMLFeature const & xmlFt, StringUtf8Multilang const & names)
{
  double score = 0;
  names.ForEach([&score, &xmlFt](uint8_t const langCode, string const & name)
                {
                  if (xmlFt.GetName(langCode) == name)
                    score += 1;
                  return true;
                });

  // TODO(mgsergio): Deafult name match should have greater wieght. Should it?

  return score;
}

vector<string> GetOsmOriginalTagsForType(feature::Metadata::EType const et)
{
  static multimap<feature::Metadata::EType, string> const kFmd2Osm = {
    {feature::Metadata::EType::FMD_CUISINE, "cuisine"},
    {feature::Metadata::EType::FMD_OPEN_HOURS, "opening_hours"},
    {feature::Metadata::EType::FMD_PHONE_NUMBER, "phone"},
    {feature::Metadata::EType::FMD_PHONE_NUMBER, "contact:phone"},
    {feature::Metadata::EType::FMD_FAX_NUMBER, "fax"},
    {feature::Metadata::EType::FMD_FAX_NUMBER, "contact:fax"},
    {feature::Metadata::EType::FMD_STARS, "stars"},
    {feature::Metadata::EType::FMD_OPERATOR, "operator"},
    {feature::Metadata::EType::FMD_URL, "url"},
    {feature::Metadata::EType::FMD_WEBSITE, "website"},
    {feature::Metadata::EType::FMD_WEBSITE, "contact:website"},
    // TODO: {feature::Metadata::EType::FMD_INTERNET, ""},
    {feature::Metadata::EType::FMD_ELE, "ele"},
    {feature::Metadata::EType::FMD_TURN_LANES, "turn:lanes"},
    {feature::Metadata::EType::FMD_TURN_LANES_FORWARD, "turn:lanes:forward"},
    {feature::Metadata::EType::FMD_TURN_LANES_BACKWARD, "turn:lanes:backward"},
    {feature::Metadata::EType::FMD_EMAIL, "email"},
    {feature::Metadata::EType::FMD_EMAIL, "contact:email"},
    {feature::Metadata::EType::FMD_POSTCODE, "addr:postcode"},
    {feature::Metadata::EType::FMD_WIKIPEDIA, "wikipedia"},
    {feature::Metadata::EType::FMD_MAXSPEED, "maxspeed"},
    {feature::Metadata::EType::FMD_FLATS, "addr:flats"},
    {feature::Metadata::EType::FMD_HEIGHT, "height"},
    {feature::Metadata::EType::FMD_MIN_HEIGHT, "min_height"},
    {feature::Metadata::EType::FMD_MIN_HEIGHT, "building:min_level"},
    {feature::Metadata::EType::FMD_DENOMINATION, "denomination"},
    {feature::Metadata::EType::FMD_BUILDING_LEVELS, "building:levels"},
  };

  vector<string> result;
  auto const range = kFmd2Osm.equal_range(et);
  for (auto it = range.first; it != range.second; ++it)
    result.emplace_back(it->second);

  return result;
}

double ScoreMetadata(XMLFeature const & xmlFt, feature::Metadata const & metadata)
{
  double score = 0;

  for (auto const type : metadata.GetPresentTypes())
  {
    for (auto const osm_tag : GetOsmOriginalTagsForType(static_cast<feature::Metadata::EType>(type)))
    {
      if (xmlFt.GetTagValue(osm_tag) == metadata.Get(type))
      {
        score += 1;
        break;
      }
    }
  }

  return score;
}

bool TypesEqual(XMLFeature const & xmlFt, feature::TypesHolder const & types)
{
  return false;
}

pugi::xml_node GetBestOsmNode(pugi::xml_document const & osmResponse, FeatureType const & ft)
{
  double bestScore = -1;
  pugi::xml_node bestMatchNode;

  for (auto const & xNode : osmResponse.select_nodes("node"))
  {
    try
    {
      XMLFeature xmlFt(xNode.node());

      if (!TypesEqual(xmlFt, feature::TypesHolder(ft)))
        continue;

      double nodeScore = ScoreLatLon(xmlFt, MercatorBounds::ToLatLon(ft.GetCenter()));
      if (nodeScore < 0)
        continue;

      nodeScore += ScoreNames(xmlFt, ft.GetNames());
      nodeScore += ScoreMetadata(xmlFt, ft.GetMetadata());

      if (bestScore < nodeScore)
      {
        bestScore = nodeScore;
        bestMatchNode = xNode.node();
      }
    }
    catch (editor::XMLFeatureNoLatLonError const & ex)
    {
      LOG(LWARNING, ("No lat/lon attribute in osm response node.", ex.Msg()));
      continue;
    }
  }

  // TODO(mgsergio): Add a properly defined threshold.
  // if (bestScore < minimumScoreThreshold)
  //   return pugi::xml_node;

  return bestMatchNode;
}
}  // namespace

string DebugPrint(pugi::xml_document const & doc)
{
  ostringstream stream;
  doc.print(stream, "  ");
  return stream.str();
}

namespace osm
{

ChangesetWrapper::ChangesetWrapper(TKeySecret const & keySecret,
                                   ServerApi06::TKeyValueTags const & comments)
  : m_changesetComments(comments),
    m_api(OsmOAuth::ServerAuth().SetToken(keySecret))
{
}

ChangesetWrapper::~ChangesetWrapper()
{
  if (m_changesetId)
    m_api.CloseChangeSet(m_changesetId);
}

void ChangesetWrapper::LoadXmlFromOSM(ms::LatLon const & ll, pugi::xml_document & doc)
{
  auto const response = m_api.GetXmlFeaturesAtLatLon(ll.lat, ll.lon);
  if (response.first == OsmOAuth::ResponseCode::NetworkError)
    MYTHROW(NetworkErrorException, ("NetworkError with GetXmlFeaturesAtLatLon request."));
  if (response.first != OsmOAuth::ResponseCode::OK)
    MYTHROW(HttpErrorException, ("HTTP error", response.first, "with GetXmlFeaturesAtLatLon", ll));

  if (pugi::status_ok != doc.load(response.second.c_str()).status)
    MYTHROW(OsmXmlParseException, ("Can't parse OSM server response for GetXmlFeaturesAtLatLon request", response.second));
}

XMLFeature ChangesetWrapper::GetMatchingFeatureFromOSM(XMLFeature const & ourPatch, FeatureType const & feature)
{
  if (feature.GetFeatureType() == feature::EGeomType::GEOM_POINT)
  {
    // Match with OSM node.
    ms::LatLon const ll = ourPatch.GetCenter();
    pugi::xml_document doc;
    // Throws!
    LoadXmlFromOSM(ll, doc);

    // feature must be the original one, not patched!
    pugi::xml_node const bestNode = GetBestOsmNode(doc, feature);
    if (bestNode.empty())
      MYTHROW(OsmObjectWasDeletedException, ("OSM does not have any nodes at the coordinates", ll, ", server has returned:", doc));

    return XMLFeature(bestNode);
  }
  else if (feature.GetFeatureType() == feature::EGeomType::GEOM_AREA)
  {
    using m2::PointD;
    // Set filters out duplicate points for closed ways or triangles' vertices.
    set<PointD> geometry;
    feature.ForEachTriangle([&geometry](PointD const & p1, PointD const & p2, PointD const & p3)
    {
      geometry.insert(p1);
      geometry.insert(p2);
      geometry.insert(p3);
    }, FeatureType::BEST_GEOMETRY);

    ASSERT_GREATER_OR_EQUAL(geometry.size(), 3, ("Is it an area feature?"));

    for (auto const & pt : geometry)
    {
      ms::LatLon const ll = MercatorBounds::ToLatLon(pt);
      pugi::xml_document doc;
      // Throws!
      LoadXmlFromOSM(ll, doc);

      // TODO(AlexZ): Select best matching OSM way from possible many ways.
      pugi::xml_node const firstWay = doc.child("osm").child("way");
      if (firstWay.empty())
        continue;

      XMLFeature const way(firstWay);
      if (!way.IsArea())
        continue;

      // TODO: Check that this way is really match our feature.

      return way;
    }
    MYTHROW(OsmObjectWasDeletedException, ("OSM does not have any matching way for feature", feature));
  }
  MYTHROW(LinearFeaturesAreNotSupportedException, ("We don't edit linear features yet."));
}

void ChangesetWrapper::ModifyNode(XMLFeature node)
{
  // TODO(AlexZ): ServerApi can be much better with exceptions.
  if (m_changesetId == kInvalidChangesetId && !m_api.CreateChangeSet(m_changesetComments, m_changesetId))
    MYTHROW(CreateChangeSetFailedException, ("CreateChangeSetFailedException"));

  uint64_t nodeId;
  if (!strings::to_uint64(node.GetAttribute("id"), nodeId))
    MYTHROW(CreateChangeSetFailedException, ("CreateChangeSetFailedException"));

  // Changeset id should be updated for every OSM server commit.
  node.SetAttribute("changeset", strings::to_string(m_changesetId));

  if (!m_api.ModifyNode(node.ToOSMString(), nodeId))
    MYTHROW(ModifyNodeFailedException, ("ModifyNodeFailedException"));
}

} // namespace osm
<commit_msg>Add GetBestOsmWay.<commit_after>#include "base/logging.hpp"

#include "indexer/feature.hpp"

#include "editor/changeset_wrapper.hpp"

#include "std/algorithm.hpp"
#include "std/sstream.hpp"
#include "std/map.hpp"

#include "geometry/mercator.hpp"

#include "private.h"

using editor::XMLFeature;

using TGeometry = set<m2::PointD>;

namespace
{
bool LatLonEqual(ms::LatLon const & a, ms::LatLon const & b)
{
  double constexpr eps = MercatorBounds::GetCellID2PointAbsEpsilon();
  return a.EqualDxDy(b, eps);
}

double ScoreLatLon(XMLFeature const & xmlFt, ms::LatLon const & latLon)
{
  // TODO: Find proper score values;
  return LatLonEqual(latLon, xmlFt.GetCenter()) ? 10 : -10;
}

double ScoreGeometry(pugi::xml_document const & osmResponse, pugi::xml_node const & way,
                     TGeometry geometry)
{
  int matched = 0;
  int total = 0;
  // TODO(mgsergio): optimize using sorting and scaning eps-squares.
  // The idea is to build squares with side = eps on points from the first set.
  // Sort them by y and x in y groups.
  // Then pass points from the second set through constructed struct and register events
  // like square started, square ended, point encounted.

  for (auto const xNodeRef : way.select_nodes("nd/@ref"))
  {
    ++total;
    string const nodeRef = xNodeRef.attribute().value();
    auto const node = osmResponse.select_node(("node[@ref='" + nodeRef + "']").data()).node();
    if (!node)
    {
      LOG(LDEBUG, ("OSM response have ref", nodeRef,
                   "but have no node with such id.", osmResponse));
      continue;  // TODO: or break and return -1000?
    }

    XMLFeature xmlFt(node);
    for (auto pointIt = begin(geometry); pointIt != end(geometry); ++pointIt)
    {
      if (LatLonEqual(xmlFt.GetCenter(), MercatorBounds::ToLatLon(*pointIt)))
      {
        ++matched;
        geometry.erase(pointIt);
      }
    }
  }

  return static_cast<double>(matched) / total * 100;
}

double ScoreNames(XMLFeature const & xmlFt, StringUtf8Multilang const & names)
{
  double score = 0;
  names.ForEach([&score, &xmlFt](uint8_t const langCode, string const & name)
                {
                  if (xmlFt.GetName(langCode) == name)
                    score += 1;
                  return true;
                });

  // TODO(mgsergio): Deafult name match should have greater wieght. Should it?

  return score;
}

vector<string> GetOsmOriginalTagsForType(feature::Metadata::EType const et)
{
  static multimap<feature::Metadata::EType, string> const kFmd2Osm = {
    {feature::Metadata::EType::FMD_CUISINE, "cuisine"},
    {feature::Metadata::EType::FMD_OPEN_HOURS, "opening_hours"},
    {feature::Metadata::EType::FMD_PHONE_NUMBER, "phone"},
    {feature::Metadata::EType::FMD_PHONE_NUMBER, "contact:phone"},
    {feature::Metadata::EType::FMD_FAX_NUMBER, "fax"},
    {feature::Metadata::EType::FMD_FAX_NUMBER, "contact:fax"},
    {feature::Metadata::EType::FMD_STARS, "stars"},
    {feature::Metadata::EType::FMD_OPERATOR, "operator"},
    {feature::Metadata::EType::FMD_URL, "url"},
    {feature::Metadata::EType::FMD_WEBSITE, "website"},
    {feature::Metadata::EType::FMD_WEBSITE, "contact:website"},
    // TODO: {feature::Metadata::EType::FMD_INTERNET, ""},
    {feature::Metadata::EType::FMD_ELE, "ele"},
    {feature::Metadata::EType::FMD_TURN_LANES, "turn:lanes"},
    {feature::Metadata::EType::FMD_TURN_LANES_FORWARD, "turn:lanes:forward"},
    {feature::Metadata::EType::FMD_TURN_LANES_BACKWARD, "turn:lanes:backward"},
    {feature::Metadata::EType::FMD_EMAIL, "email"},
    {feature::Metadata::EType::FMD_EMAIL, "contact:email"},
    {feature::Metadata::EType::FMD_POSTCODE, "addr:postcode"},
    {feature::Metadata::EType::FMD_WIKIPEDIA, "wikipedia"},
    {feature::Metadata::EType::FMD_MAXSPEED, "maxspeed"},
    {feature::Metadata::EType::FMD_FLATS, "addr:flats"},
    {feature::Metadata::EType::FMD_HEIGHT, "height"},
    {feature::Metadata::EType::FMD_MIN_HEIGHT, "min_height"},
    {feature::Metadata::EType::FMD_MIN_HEIGHT, "building:min_level"},
    {feature::Metadata::EType::FMD_DENOMINATION, "denomination"},
    {feature::Metadata::EType::FMD_BUILDING_LEVELS, "building:levels"},
  };

  vector<string> result;
  auto const range = kFmd2Osm.equal_range(et);
  for (auto it = range.first; it != range.second; ++it)
    result.emplace_back(it->second);

  return result;
}

double ScoreMetadata(XMLFeature const & xmlFt, feature::Metadata const & metadata)
{
  double score = 0;

  for (auto const type : metadata.GetPresentTypes())
  {
    for (auto const osm_tag : GetOsmOriginalTagsForType(static_cast<feature::Metadata::EType>(type)))
    {
      if (xmlFt.GetTagValue(osm_tag) == metadata.Get(type))
      {
        score += 1;
        break;
      }
    }
  }

  return score;
}

bool TypesEqual(XMLFeature const & xmlFt, feature::TypesHolder const & types)
{
  return false;
}

pugi::xml_node GetBestOsmNode(pugi::xml_document const & osmResponse, FeatureType const & ft)
{
  double bestScore = -1;
  pugi::xml_node bestMatchNode;

  for (auto const & xNode : osmResponse.select_nodes("node"))
  {
    try
    {
      XMLFeature xmlFt(xNode.node());

      if (!TypesEqual(xmlFt, feature::TypesHolder(ft)))
        continue;

      double nodeScore = ScoreLatLon(xmlFt, MercatorBounds::ToLatLon(ft.GetCenter()));
      if (nodeScore < 0)
        continue;

      nodeScore += ScoreNames(xmlFt, ft.GetNames());
      nodeScore += ScoreMetadata(xmlFt, ft.GetMetadata());

      if (bestScore < nodeScore)
      {
        bestScore = nodeScore;
        bestMatchNode = xNode.node();
      }
    }
    catch (editor::XMLFeatureNoLatLonError const & ex)
    {
      LOG(LWARNING, ("No lat/lon attribute in osm response node.", ex.Msg()));
      continue;
    }
  }

  // TODO(mgsergio): Add a properly defined threshold.
  // if (bestScore < minimumScoreThreshold)
  //   return pugi::xml_node;

  return bestMatchNode;
}

pugi::xml_node GetBestOsmWay(pugi::xml_document const & osmResponse, FeatureType const & ft,
                             TGeometry const & geometry)
{
  double bestScore = -1;
  pugi::xml_node bestMatchWay;

  for (auto const & xWay : osmResponse.select_nodes("Way"))
  {
    try
    {
      XMLFeature xmlFt(xWay.node());

      if (!TypesEqual(xmlFt, feature::TypesHolder(ft)))
        continue;

      double nodeScore = ScoreGeometry(osmResponse, xWay.node(), geometry);
      if (nodeScore < 0)
        continue;

      nodeScore += ScoreNames(xmlFt, ft.GetNames());
      nodeScore += ScoreMetadata(xmlFt, ft.GetMetadata());

      if (bestScore < nodeScore)
      {
        bestScore = nodeScore;
        bestMatchWay = xWay.node();
      }
    }
    catch (editor::XMLFeatureNoLatLonError const & ex)
    {
      LOG(LWARNING, ("No lat/lon attribute in osm response node.", ex.Msg()));
      continue;
    }
  }

  // TODO(mgsergio): Add a properly defined threshold.
  // if (bestScore < minimumScoreThreshold)
  //   return pugi::xml_node;

  return bestMatchWay;
}

}  // namespace

string DebugPrint(pugi::xml_document const & doc)
{
  ostringstream stream;
  doc.print(stream, "  ");
  return stream.str();
}

namespace osm
{

ChangesetWrapper::ChangesetWrapper(TKeySecret const & keySecret,
                                   ServerApi06::TKeyValueTags const & comments)
  : m_changesetComments(comments),
    m_api(OsmOAuth::ServerAuth().SetToken(keySecret))
{
}

ChangesetWrapper::~ChangesetWrapper()
{
  if (m_changesetId)
    m_api.CloseChangeSet(m_changesetId);
}

void ChangesetWrapper::LoadXmlFromOSM(ms::LatLon const & ll, pugi::xml_document & doc)
{
  auto const response = m_api.GetXmlFeaturesAtLatLon(ll.lat, ll.lon);
  if (response.first == OsmOAuth::ResponseCode::NetworkError)
    MYTHROW(NetworkErrorException, ("NetworkError with GetXmlFeaturesAtLatLon request."));
  if (response.first != OsmOAuth::ResponseCode::OK)
    MYTHROW(HttpErrorException, ("HTTP error", response.first, "with GetXmlFeaturesAtLatLon", ll));

  if (pugi::status_ok != doc.load(response.second.c_str()).status)
    MYTHROW(OsmXmlParseException, ("Can't parse OSM server response for GetXmlFeaturesAtLatLon request", response.second));
}

XMLFeature ChangesetWrapper::GetMatchingFeatureFromOSM(XMLFeature const & ourPatch, FeatureType const & feature)
{
  if (feature.GetFeatureType() == feature::EGeomType::GEOM_POINT)
  {
    // Match with OSM node.
    ms::LatLon const ll = ourPatch.GetCenter();
    pugi::xml_document doc;
    // Throws!
    LoadXmlFromOSM(ll, doc);

    // feature must be the original one, not patched!
    pugi::xml_node const bestNode = GetBestOsmNode(doc, feature);
    if (bestNode.empty())
      MYTHROW(OsmObjectWasDeletedException, ("OSM does not have any nodes at the coordinates", ll, ", server has returned:", doc));

    return XMLFeature(bestNode);
  }
  else if (feature.GetFeatureType() == feature::EGeomType::GEOM_AREA)
  {
    using m2::PointD;
    // Set filters out duplicate points for closed ways or triangles' vertices.
    TGeometry geometry;
    feature.ForEachTriangle([&geometry](PointD const & p1, PointD const & p2, PointD const & p3)
    {
      geometry.insert(p1);
      geometry.insert(p2);
      geometry.insert(p3);
    }, FeatureType::BEST_GEOMETRY);

    ASSERT_GREATER_OR_EQUAL(geometry.size(), 3, ("Is it an area feature?"));

    for (auto const & pt : geometry)
    {
      ms::LatLon const ll = MercatorBounds::ToLatLon(pt);
      pugi::xml_document doc;
      // Throws!
      LoadXmlFromOSM(ll, doc);

      // TODO(AlexZ): Select best matching OSM way from possible many ways.
      pugi::xml_node const bestWay = GetBestOsmWay(doc, feature, geometry);
      if (bestWay.empty())
        continue;

      XMLFeature const way(bestWay);
      if (!way.IsArea())
        continue;

      // TODO: Check that this way is really match our feature.

      return way;
    }
    MYTHROW(OsmObjectWasDeletedException, ("OSM does not have any matching way for feature", feature));
  }
  MYTHROW(LinearFeaturesAreNotSupportedException, ("We don't edit linear features yet."));
}

void ChangesetWrapper::ModifyNode(XMLFeature node)
{
  // TODO(AlexZ): ServerApi can be much better with exceptions.
  if (m_changesetId == kInvalidChangesetId && !m_api.CreateChangeSet(m_changesetComments, m_changesetId))
    MYTHROW(CreateChangeSetFailedException, ("CreateChangeSetFailedException"));

  uint64_t nodeId;
  if (!strings::to_uint64(node.GetAttribute("id"), nodeId))
    MYTHROW(CreateChangeSetFailedException, ("CreateChangeSetFailedException"));

  // Changeset id should be updated for every OSM server commit.
  node.SetAttribute("changeset", strings::to_string(m_changesetId));

  if (!m_api.ModifyNode(node.ToOSMString(), nodeId))
    MYTHROW(ModifyNodeFailedException, ("ModifyNodeFailedException"));
}

} // namespace osm
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <chrono>
#include <cstdio>
#include <string>
#include <vector>
#include <sdbusplus/vtable.hpp>
#include <systemd/sd-bus.h>
#include <systemd/sd-journal.h>
#include "elog-lookup.cpp"
#include <phosphor-logging/elog-errors-HostEvent.hpp>
#include "config.h"
#include "elog_entry.hpp"
#include <phosphor-logging/log.hpp>
#include "log_manager.hpp"

namespace phosphor
{
namespace logging
{

void Manager::commit(uint64_t transactionId, std::string errMsg)
{
    // TODO Change /tmp path to a permanent location on flash
    constexpr const auto path = "/tmp/elog";
    constexpr const auto transactionIdVar = "TRANSACTION_ID";

    std::string filename{};
    filename.append(path);
    // TODO Create error logs in their own separate dir once permanent location
    // on flash is determined. Ex: ../transactionId/1
    std::ofstream efile;
    efile.open(filename);
    efile << "{" << std::endl;

    sd_journal *j = nullptr;
    int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
    if (rc < 0)
    {
        logging::log<logging::level::ERR>("Failed to open journal",
                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
        return;
    }

    std::string transactionIdStr = std::to_string(transactionId);
    std::vector<std::string> metalist = g_errMetaMap[errMsg];
    std::vector<std::string> metalistHostEvent = g_errMetaMapHostEvent[errMsg];
    std::vector<std::string> additionalData;

    // Read the journal from the end to get the most recent entry first.
    // The result from the sd_journal_get_data() is of the form VARIABLE=value.
    SD_JOURNAL_FOREACH_BACKWARDS(j)
    {
        const char *data = nullptr;
        size_t length = 0;

        // Look for the transaction id metadata variable
        rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data,
                                &length);
        if (rc < 0)
        {
            // This journal entry does not have the transaction id,
            // continue to next entry
            continue;
        }

        std::string result(data);
        if (result.find(transactionIdStr) == std::string::npos)
        {
            // Requested transaction id  not found,
            // continue to next journal entry.
            continue;
        }
        // Match found, write to file
        // TODO This is a draft format based on the redfish event logs written
        // in json, the final openbmc format is to be determined
        efile << "\t{" << std::endl;
        efile << "\t\"@" << data << "\"," << std::endl;

        // Include the journal message
        rc = sd_journal_get_data(j, "MESSAGE", (const void **)&data, &length);
        if (rc < 0)
        {
            continue;
        }

        efile << "\t\"@" << data << "\"," << std::endl;

        // Search for the metadata variables in the current journal entry
        for (auto metaVarStr : metalist)
        {
            rc = sd_journal_get_data(j, metaVarStr.c_str(),
                                    (const void **)&data, &length);
            if (rc < 0)
            {
                // Not found, continue to next metadata variable
                logging::log<logging::level::INFO>("Failed to find metadata",
                        logging::entry("META_FIELD=%s", metaVarStr.c_str()));
                continue;
            }

            // Metatdata variable found, write to file
            additionalData.push_back(std::string(data));
            efile << "\t\"@" << data << "\"," << std::endl;
        }
        efile << "\t}" << std::endl;

        // TODO Remove once host event error header file is auto-generated.
        // Tracking with issue openbmc/phosphor-logging#4
        for (auto metaVarStrHostEvent : metalistHostEvent)
        {
            rc = sd_journal_get_data(j, metaVarStrHostEvent.c_str(),
                                    (const void **)&data, &length);
            if (rc < 0)
            {
                // Not found, continue to next metadata variable
                logging::log<logging::level::INFO>("Failed to find metadata",
                        logging::entry("META_FIELD=%s",
                        metaVarStrHostEvent.c_str()));
                continue;
            }

            // Metatdata variable found, write to file
            additionalData.push_back(std::string(data));
            efile << "\t\"@" << data << "\"," << std::endl;
        }

        // TODO Break only once all metadata fields have been found. Implement
        // once this function reads the metadata fields from the header file.
        break;
    }
    sd_journal_close(j);

    // Create error Entry dbus object
    entryId++;
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::system_clock::now().time_since_epoch()).count();
    auto objPath =  std::string(OBJ_ENTRY) + '/' +
            std::to_string(entryId);
    entries.insert(std::make_pair(entryId, std::make_unique<Entry>(
            busLog,
            objPath,
            entryId,
            ms, // Milliseconds since 1970
            (Entry::Level)g_errLevelMap[errMsg],
            std::move(errMsg),
            std::move(additionalData))));

    efile << "}" << std::endl;
    efile.close();
    return;
}

} // namespace logging
} // namepsace phosphor
<commit_msg>commit: Remove unused code<commit_after>#include <fstream>
#include <iostream>
#include <chrono>
#include <cstdio>
#include <string>
#include <vector>
#include <sdbusplus/vtable.hpp>
#include <systemd/sd-bus.h>
#include <systemd/sd-journal.h>
#include "elog-lookup.cpp"
#include <phosphor-logging/elog-errors-HostEvent.hpp>
#include "config.h"
#include "elog_entry.hpp"
#include <phosphor-logging/log.hpp>
#include "log_manager.hpp"

namespace phosphor
{
namespace logging
{

void Manager::commit(uint64_t transactionId, std::string errMsg)
{
    constexpr const auto transactionIdVar = "TRANSACTION_ID";

    sd_journal *j = nullptr;
    int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
    if (rc < 0)
    {
        logging::log<logging::level::ERR>("Failed to open journal",
                           logging::entry("DESCRIPTION=%s", strerror(-rc)));
        return;
    }

    std::string transactionIdStr = std::to_string(transactionId);
    std::vector<std::string> metalist = g_errMetaMap[errMsg];
    std::vector<std::string> metalistHostEvent = g_errMetaMapHostEvent[errMsg];
    std::vector<std::string> additionalData;

    // Read the journal from the end to get the most recent entry first.
    // The result from the sd_journal_get_data() is of the form VARIABLE=value.
    SD_JOURNAL_FOREACH_BACKWARDS(j)
    {
        const char *data = nullptr;
        size_t length = 0;

        // Look for the transaction id metadata variable
        rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data,
                                &length);
        if (rc < 0)
        {
            // This journal entry does not have the transaction id,
            // continue to next entry
            continue;
        }

        std::string result(data);
        if (result.find(transactionIdStr) == std::string::npos)
        {
            // Requested transaction id  not found,
            // continue to next journal entry.
            continue;
        }

        // Search for the metadata variables in the current journal entry
        for (auto metaVarStr : metalist)
        {
            rc = sd_journal_get_data(j, metaVarStr.c_str(),
                                    (const void **)&data, &length);
            if (rc < 0)
            {
                // Not found, continue to next metadata variable
                logging::log<logging::level::INFO>("Failed to find metadata",
                        logging::entry("META_FIELD=%s", metaVarStr.c_str()));
                continue;
            }

            // Metatdata variable found, write to file
            additionalData.push_back(std::string(data));
        }

        // TODO Remove once host event error header file is auto-generated.
        // Tracking with issue openbmc/phosphor-logging#4
        for (auto metaVarStrHostEvent : metalistHostEvent)
        {
            rc = sd_journal_get_data(j, metaVarStrHostEvent.c_str(),
                                    (const void **)&data, &length);
            if (rc < 0)
            {
                // Not found, continue to next metadata variable
                logging::log<logging::level::INFO>("Failed to find metadata",
                        logging::entry("META_FIELD=%s",
                        metaVarStrHostEvent.c_str()));
                continue;
            }

            // Metatdata variable found, write to file
            additionalData.push_back(std::string(data));
        }

        // TODO Break only once all metadata fields have been found. Implement
        // once this function reads the metadata fields from the header file.
        break;
    }
    sd_journal_close(j);

    // Create error Entry dbus object
    entryId++;
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::system_clock::now().time_since_epoch()).count();
    auto objPath =  std::string(OBJ_ENTRY) + '/' +
            std::to_string(entryId);
    entries.insert(std::make_pair(entryId, std::make_unique<Entry>(
            busLog,
            objPath,
            entryId,
            ms, // Milliseconds since 1970
            (Entry::Level)g_errLevelMap[errMsg],
            std::move(errMsg),
            std::move(additionalData))));
    return;
}

} // namespace logging
} // namepsace phosphor
<|endoftext|>