<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/platform_util.h"

#include <windows.h>  // windows.h must be included first

#include <atlbase.h>
#include <comdef.h>
#include <commdlg.h>
#include <dwmapi.h>
#include <shellapi.h>
#include <shlobj.h>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "ui/base/win/shell.h"
#include "url/gurl.h"

namespace {

// Old ShellExecute crashes the process when the command for a given scheme
// is empty. This function tells if it is.
bool ValidateShellCommandForScheme(const std::string& scheme) {
  base::win::RegKey key;
  base::string16 registry_path = base::ASCIIToUTF16(scheme) +
                                 L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
  if (!key.Valid())
    return false;
  DWORD size = 0;
  key.ReadValue(NULL, NULL, &size, NULL);
  if (size <= 2)
    return false;
  return true;
}

// Required COM implementation of IFileOperationProgressSink so we can
// precheck files before deletion to make sure they can be move to the
// Recycle Bin.
class DeleteFileProgressSink : public IFileOperationProgressSink {
 public:
  DeleteFileProgressSink();

 private:
  ULONG STDMETHODCALLTYPE AddRef(void);
  ULONG STDMETHODCALLTYPE Release(void);
  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj);
  HRESULT STDMETHODCALLTYPE StartOperations(void);
  HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT);
  HRESULT STDMETHODCALLTYPE PreRenameItem(
      DWORD, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostRenameItem(
      DWORD, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreMoveItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostMoveItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreCopyItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostCopyItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD, IShellItem*);
  HRESULT STDMETHODCALLTYPE PostDeleteItem(
      DWORD, IShellItem*, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreNewItem(
      DWORD, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostNewItem(
      DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT);
  HRESULT STDMETHODCALLTYPE ResetTimer(void);
  HRESULT STDMETHODCALLTYPE PauseTimer(void);
  HRESULT STDMETHODCALLTYPE ResumeTimer(void);

  ULONG m_cRef;
};

DeleteFileProgressSink::DeleteFileProgressSink() {
  m_cRef = 0;
}

HRESULT DeleteFileProgressSink::PreDeleteItem(DWORD dwFlags, IShellItem*) {
  if (!(dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE)) {
    // TSF_DELETE_RECYCLE_IF_POSSIBLE will not be set for items that cannot be
    // recycled.  In this case, we abort the delete operation.  This bubbles
    // up and stops the Delete in IFileOperation.
    return E_ABORT;
  }
  // Returns S_OK if successful, or an error value otherwise. In the case of an
  // error value, the delete operation and all subsequent operations pending
  // from the call to IFileOperation are canceled.
  return S_OK;
}

HRESULT DeleteFileProgressSink::QueryInterface(REFIID riid, LPVOID* ppvObj) {
  // Always set out parameter to NULL, validating it first.
  if (!ppvObj)
    return E_INVALIDARG;
  *ppvObj = nullptr;
  if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) {
    // Increment the reference count and return the pointer.
    *ppvObj = reinterpret_cast<IUnknown*>(this);
    AddRef();
    return NOERROR;
  }
  return E_NOINTERFACE;
}

ULONG DeleteFileProgressSink::AddRef() {
  InterlockedIncrement(&m_cRef);
  return m_cRef;
}

ULONG DeleteFileProgressSink::Release() {
  // Decrement the object's internal counter.
  ULONG ulRefCount = InterlockedDecrement(&m_cRef);
  if (0 == m_cRef) {
    delete this;
  }
  return ulRefCount;
}

HRESULT DeleteFileProgressSink::StartOperations() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::FinishOperations(HRESULT) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PreRenameItem(DWORD, IShellItem*, LPCWSTR) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PostRenameItem(
    DWORD, IShellItem*, __RPC__in_string LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PreMoveItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostMoveItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PreCopyItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostCopyItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostDeleteItem(
    DWORD, IShellItem*, HRESULT, IShellItem*) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PreNewItem(
    DWORD dwFlags, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostNewItem(
    DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::UpdateProgress(UINT, UINT) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::ResetTimer() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PauseTimer() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::ResumeTimer() {
  return S_OK;
}

}  // namespace

namespace platform_util {

bool ShowItemInFolder(const base::FilePath& full_path) {
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return false;

  base::FilePath dir = full_path.DirName().AsEndingWithSeparator();
  // ParseDisplayName will fail if the directory is "C:", it must be "C:\\".
  if (dir.empty())
    return false;

  typedef HRESULT (WINAPI *SHOpenFolderAndSelectItemsFuncPtr)(
      PCIDLIST_ABSOLUTE pidl_Folder,
      UINT cidl,
      PCUITEMID_CHILD_ARRAY pidls,
      DWORD flags);

  static SHOpenFolderAndSelectItemsFuncPtr open_folder_and_select_itemsPtr =
    NULL;
  static bool initialize_open_folder_proc = true;
  if (initialize_open_folder_proc) {
    initialize_open_folder_proc = false;
    // The SHOpenFolderAndSelectItems API is exposed by shell32 version 6
    // and does not exist in Win2K. We attempt to retrieve this function export
    // from shell32 and if it does not exist, we just invoke ShellExecute to
    // open the folder thus losing the functionality to select the item in
    // the process.
    HMODULE shell32_base = GetModuleHandle(L"shell32.dll");
    if (!shell32_base) {
      NOTREACHED() << " " << __FUNCTION__ << "(): Can't open shell32.dll";
      return false;
    }
    open_folder_and_select_itemsPtr =
        reinterpret_cast<SHOpenFolderAndSelectItemsFuncPtr>
            (GetProcAddress(shell32_base, "SHOpenFolderAndSelectItems"));
  }
  if (!open_folder_and_select_itemsPtr) {
    return ui::win::OpenFolderViaShell(dir);
  }

  base::win::ScopedComPtr<IShellFolder> desktop;
  HRESULT hr = SHGetDesktopFolder(desktop.Receive());
  if (FAILED(hr))
    return false;

  base::win::ScopedCoMem<ITEMIDLIST> dir_item;
  hr = desktop->ParseDisplayName(NULL, NULL,
                                 const_cast<wchar_t *>(dir.value().c_str()),
                                 NULL, &dir_item, NULL);
  if (FAILED(hr)) {
    return ui::win::OpenFolderViaShell(dir);
  }

  base::win::ScopedCoMem<ITEMIDLIST> file_item;
  hr = desktop->ParseDisplayName(NULL, NULL,
      const_cast<wchar_t *>(full_path.value().c_str()),
      NULL, &file_item, NULL);
  if (FAILED(hr)) {
    return ui::win::OpenFolderViaShell(dir);
  }

  const ITEMIDLIST* highlight[] = { file_item };

  hr = (*open_folder_and_select_itemsPtr)(dir_item, arraysize(highlight),
                                          highlight, NULL);
  if (!FAILED(hr))
    return true;

  // On some systems, the above call mysteriously fails with "file not
  // found" even though the file is there.  In these cases, ShellExecute()
  // seems to work as a fallback (although it won't select the file).
  if (hr == ERROR_FILE_NOT_FOUND) {
    return ui::win::OpenFolderViaShell(dir);
  } else {
    LPTSTR message = NULL;
    DWORD message_length = FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        0, hr, 0, reinterpret_cast<LPTSTR>(&message), 0, NULL);
    LOG(WARNING) << " " << __FUNCTION__
                 << "(): Can't open full_path = \""
                 << full_path.value() << "\""
                 << " hr = " << hr
                 << " " << reinterpret_cast<LPTSTR>(&message);
    if (message)
      LocalFree(message);

    return ui::win::OpenFolderViaShell(dir);
  }
}

bool OpenItem(const base::FilePath& full_path) {
  if (base::DirectoryExists(full_path))
    return ui::win::OpenFolderViaShell(full_path);
  else
    return ui::win::OpenFileViaShell(full_path);
}

bool OpenExternal(const base::string16& url, bool activate) {
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  base::string16 escaped_url = L"\"" + url + L"\"";

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteW(NULL, L"open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return false;
  }
  return true;
}

void OpenExternal(const base::string16& url, bool activate,
                  const OpenExternalCallback& callback) {
  // TODO(gabriel): Implement async open if callback is specified
  callback.Run(OpenExternal(url, activate) ? "" : "Failed to open");
}

bool MoveItemToTrash(const base::FilePath& path) {
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return false;

  base::win::ScopedComPtr<IFileOperation> pfo;
  if (FAILED(pfo.CreateInstance(CLSID_FileOperation)))
    return false;

  // Elevation prompt enabled for UAC protected files.  This overrides the
  // SILENT, NO_UI and NOERRORUI flags.

  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
    // Windows 8 introduces the flag RECYCLEONDELETE and deprecates the
    // ALLOWUNDO in favor of ADDUNDORECORD.
    if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
                                      FOFX_ADDUNDORECORD |
                                      FOF_NOERRORUI |
                                      FOF_SILENT |
                                      FOFX_SHOWELEVATIONPROMPT |
                                      FOFX_RECYCLEONDELETE)))
      return false;
  } else {
    // For Windows 7 and Vista, RecycleOnDelete is the default behavior.
    if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
                                      FOF_ALLOWUNDO |
                                      FOF_NOERRORUI |
                                      FOF_SILENT |
                                      FOFX_SHOWELEVATIONPROMPT)))
      return false;
  }

  // Create an IShellItem from the supplied source path.
  base::win::ScopedComPtr<IShellItem> delete_item;
  if (FAILED(SHCreateItemFromParsingName(path.value().c_str(),
                                         NULL,
                                         IID_PPV_ARGS(delete_item.Receive()))))
    return false;

  base::win::ScopedComPtr<IFileOperationProgressSink> delete_sink(
      new DeleteFileProgressSink);
  if (!delete_sink)
    return false;

  // Processes the queued command DeleteItem. This will trigger
  // the DeleteFileProgressSink to check for Recycle Bin.
  return SUCCEEDED(pfo->DeleteItem(delete_item.Get(), delete_sink.Get())) &&
         SUCCEEDED(pfo->PerformOperations());
}

void Beep() {
  MessageBeep(MB_OK);
}

}  // namespace platform_util
<commit_msg>Rename ScopedComPtr::Receive to ScopedComPtr::GetAddressOf<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/platform_util.h"

#include <windows.h>  // windows.h must be included first

#include <atlbase.h>
#include <comdef.h>
#include <commdlg.h>
#include <dwmapi.h>
#include <shellapi.h>
#include <shlobj.h>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "ui/base/win/shell.h"
#include "url/gurl.h"

namespace {

// Old ShellExecute crashes the process when the command for a given scheme
// is empty. This function tells if it is.
bool ValidateShellCommandForScheme(const std::string& scheme) {
  base::win::RegKey key;
  base::string16 registry_path = base::ASCIIToUTF16(scheme) +
                                 L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
  if (!key.Valid())
    return false;
  DWORD size = 0;
  key.ReadValue(NULL, NULL, &size, NULL);
  if (size <= 2)
    return false;
  return true;
}

// Required COM implementation of IFileOperationProgressSink so we can
// precheck files before deletion to make sure they can be move to the
// Recycle Bin.
class DeleteFileProgressSink : public IFileOperationProgressSink {
 public:
  DeleteFileProgressSink();

 private:
  ULONG STDMETHODCALLTYPE AddRef(void);
  ULONG STDMETHODCALLTYPE Release(void);
  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj);
  HRESULT STDMETHODCALLTYPE StartOperations(void);
  HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT);
  HRESULT STDMETHODCALLTYPE PreRenameItem(
      DWORD, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostRenameItem(
      DWORD, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreMoveItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostMoveItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreCopyItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostCopyItem(
      DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD, IShellItem*);
  HRESULT STDMETHODCALLTYPE PostDeleteItem(
      DWORD, IShellItem*, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE PreNewItem(
      DWORD, IShellItem*, LPCWSTR);
  HRESULT STDMETHODCALLTYPE PostNewItem(
      DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*);
  HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT);
  HRESULT STDMETHODCALLTYPE ResetTimer(void);
  HRESULT STDMETHODCALLTYPE PauseTimer(void);
  HRESULT STDMETHODCALLTYPE ResumeTimer(void);

  ULONG m_cRef;
};

DeleteFileProgressSink::DeleteFileProgressSink() {
  m_cRef = 0;
}

HRESULT DeleteFileProgressSink::PreDeleteItem(DWORD dwFlags, IShellItem*) {
  if (!(dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE)) {
    // TSF_DELETE_RECYCLE_IF_POSSIBLE will not be set for items that cannot be
    // recycled.  In this case, we abort the delete operation.  This bubbles
    // up and stops the Delete in IFileOperation.
    return E_ABORT;
  }
  // Returns S_OK if successful, or an error value otherwise. In the case of an
  // error value, the delete operation and all subsequent operations pending
  // from the call to IFileOperation are canceled.
  return S_OK;
}

HRESULT DeleteFileProgressSink::QueryInterface(REFIID riid, LPVOID* ppvObj) {
  // Always set out parameter to NULL, validating it first.
  if (!ppvObj)
    return E_INVALIDARG;
  *ppvObj = nullptr;
  if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) {
    // Increment the reference count and return the pointer.
    *ppvObj = reinterpret_cast<IUnknown*>(this);
    AddRef();
    return NOERROR;
  }
  return E_NOINTERFACE;
}

ULONG DeleteFileProgressSink::AddRef() {
  InterlockedIncrement(&m_cRef);
  return m_cRef;
}

ULONG DeleteFileProgressSink::Release() {
  // Decrement the object's internal counter.
  ULONG ulRefCount = InterlockedDecrement(&m_cRef);
  if (0 == m_cRef) {
    delete this;
  }
  return ulRefCount;
}

HRESULT DeleteFileProgressSink::StartOperations() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::FinishOperations(HRESULT) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PreRenameItem(DWORD, IShellItem*, LPCWSTR) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PostRenameItem(
    DWORD, IShellItem*, __RPC__in_string LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PreMoveItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostMoveItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PreCopyItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostCopyItem(
    DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostDeleteItem(
    DWORD, IShellItem*, HRESULT, IShellItem*) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PreNewItem(
    DWORD dwFlags, IShellItem*, LPCWSTR) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::PostNewItem(
    DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*) {
  return E_NOTIMPL;
}

HRESULT DeleteFileProgressSink::UpdateProgress(UINT, UINT) {
  return S_OK;
}

HRESULT DeleteFileProgressSink::ResetTimer() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::PauseTimer() {
  return S_OK;
}

HRESULT DeleteFileProgressSink::ResumeTimer() {
  return S_OK;
}

}  // namespace

namespace platform_util {

bool ShowItemInFolder(const base::FilePath& full_path) {
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return false;

  base::FilePath dir = full_path.DirName().AsEndingWithSeparator();
  // ParseDisplayName will fail if the directory is "C:", it must be "C:\\".
  if (dir.empty())
    return false;

  typedef HRESULT (WINAPI *SHOpenFolderAndSelectItemsFuncPtr)(
      PCIDLIST_ABSOLUTE pidl_Folder,
      UINT cidl,
      PCUITEMID_CHILD_ARRAY pidls,
      DWORD flags);

  static SHOpenFolderAndSelectItemsFuncPtr open_folder_and_select_itemsPtr =
    NULL;
  static bool initialize_open_folder_proc = true;
  if (initialize_open_folder_proc) {
    initialize_open_folder_proc = false;
    // The SHOpenFolderAndSelectItems API is exposed by shell32 version 6
    // and does not exist in Win2K. We attempt to retrieve this function export
    // from shell32 and if it does not exist, we just invoke ShellExecute to
    // open the folder thus losing the functionality to select the item in
    // the process.
    HMODULE shell32_base = GetModuleHandle(L"shell32.dll");
    if (!shell32_base) {
      NOTREACHED() << " " << __FUNCTION__ << "(): Can't open shell32.dll";
      return false;
    }
    open_folder_and_select_itemsPtr =
        reinterpret_cast<SHOpenFolderAndSelectItemsFuncPtr>
            (GetProcAddress(shell32_base, "SHOpenFolderAndSelectItems"));
  }
  if (!open_folder_and_select_itemsPtr) {
    return ui::win::OpenFolderViaShell(dir);
  }

  base::win::ScopedComPtr<IShellFolder> desktop;
  HRESULT hr = SHGetDesktopFolder(desktop.GetAddressOf());
  if (FAILED(hr))
    return false;

  base::win::ScopedCoMem<ITEMIDLIST> dir_item;
  hr = desktop->ParseDisplayName(NULL, NULL,
                                 const_cast<wchar_t *>(dir.value().c_str()),
                                 NULL, &dir_item, NULL);
  if (FAILED(hr)) {
    return ui::win::OpenFolderViaShell(dir);
  }

  base::win::ScopedCoMem<ITEMIDLIST> file_item;
  hr = desktop->ParseDisplayName(NULL, NULL,
      const_cast<wchar_t *>(full_path.value().c_str()),
      NULL, &file_item, NULL);
  if (FAILED(hr)) {
    return ui::win::OpenFolderViaShell(dir);
  }

  const ITEMIDLIST* highlight[] = { file_item };

  hr = (*open_folder_and_select_itemsPtr)(dir_item, arraysize(highlight),
                                          highlight, NULL);
  if (!FAILED(hr))
    return true;

  // On some systems, the above call mysteriously fails with "file not
  // found" even though the file is there.  In these cases, ShellExecute()
  // seems to work as a fallback (although it won't select the file).
  if (hr == ERROR_FILE_NOT_FOUND) {
    return ui::win::OpenFolderViaShell(dir);
  } else {
    LPTSTR message = NULL;
    DWORD message_length = FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        0, hr, 0, reinterpret_cast<LPTSTR>(&message), 0, NULL);
    LOG(WARNING) << " " << __FUNCTION__
                 << "(): Can't open full_path = \""
                 << full_path.value() << "\""
                 << " hr = " << hr
                 << " " << reinterpret_cast<LPTSTR>(&message);
    if (message)
      LocalFree(message);

    return ui::win::OpenFolderViaShell(dir);
  }
}

bool OpenItem(const base::FilePath& full_path) {
  if (base::DirectoryExists(full_path))
    return ui::win::OpenFolderViaShell(full_path);
  else
    return ui::win::OpenFileViaShell(full_path);
}

bool OpenExternal(const base::string16& url, bool activate) {
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  base::string16 escaped_url = L"\"" + url + L"\"";

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteW(NULL, L"open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return false;
  }
  return true;
}

void OpenExternal(const base::string16& url, bool activate,
                  const OpenExternalCallback& callback) {
  // TODO(gabriel): Implement async open if callback is specified
  callback.Run(OpenExternal(url, activate) ? "" : "Failed to open");
}

bool MoveItemToTrash(const base::FilePath& path) {
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return false;

  base::win::ScopedComPtr<IFileOperation> pfo;
  if (FAILED(pfo.CreateInstance(CLSID_FileOperation)))
    return false;

  // Elevation prompt enabled for UAC protected files.  This overrides the
  // SILENT, NO_UI and NOERRORUI flags.

  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
    // Windows 8 introduces the flag RECYCLEONDELETE and deprecates the
    // ALLOWUNDO in favor of ADDUNDORECORD.
    if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
                                      FOFX_ADDUNDORECORD |
                                      FOF_NOERRORUI |
                                      FOF_SILENT |
                                      FOFX_SHOWELEVATIONPROMPT |
                                      FOFX_RECYCLEONDELETE)))
      return false;
  } else {
    // For Windows 7 and Vista, RecycleOnDelete is the default behavior.
    if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
                                      FOF_ALLOWUNDO |
                                      FOF_NOERRORUI |
                                      FOF_SILENT |
                                      FOFX_SHOWELEVATIONPROMPT)))
      return false;
  }

  // Create an IShellItem from the supplied source path.
  base::win::ScopedComPtr<IShellItem> delete_item;
  if (FAILED(SHCreateItemFromParsingName(
      path.value().c_str(),
      NULL,
      IID_PPV_ARGS(delete_item.GetAddressOf()))))
    return false;

  base::win::ScopedComPtr<IFileOperationProgressSink> delete_sink(
      new DeleteFileProgressSink);
  if (!delete_sink)
    return false;

  // Processes the queued command DeleteItem. This will trigger
  // the DeleteFileProgressSink to check for Recycle Bin.
  return SUCCEEDED(pfo->DeleteItem(delete_item.Get(), delete_sink.Get())) &&
         SUCCEEDED(pfo->PerformOperations());
}

void Beep() {
  MessageBeep(MB_OK);
}

}  // namespace platform_util
<|endoftext|>


<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file llvm_to_gen.cpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */

#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/DataLayout.h"
#else
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DataLayout.h"
#endif  /* LLVM_VERSION_MINOR <= 2 */
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/ADT/Triple.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2
#include "llvm/Support/IRReader.h"
#else
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#endif  /* LLVM_VERSION_MINOR <= 2 */
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/Verifier.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#endif

#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/llvm_gen_backend.hpp"
#include "llvm/llvm_to_gen.hpp"
#include "sys/cvar.hpp"
#include "sys/platform.hpp"

#include <clang/CodeGen/CodeGenAction.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <memory>

namespace gbe
{
  BVAR(OCL_OUTPUT_LLVM, false);
  BVAR(OCL_OUTPUT_CFG, false);
  BVAR(OCL_OUTPUT_CFG_ONLY, false);
  BVAR(OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS, false);
  using namespace llvm;

  void runFuntionPass(Module &mod, TargetLibraryInfo *libraryInfo)
  {
    FunctionPassManager FPM(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    FPM.add(new DataLayoutPass(&mod));
#else
    FPM.add(new DataLayout(&mod));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
    FPM.add(createVerifierPass(true));
#else
    FPM.add(createVerifierPass());
#endif
    FPM.add(new TargetLibraryInfo(*libraryInfo));
    FPM.add(createTypeBasedAliasAnalysisPass());
    FPM.add(createBasicAliasAnalysisPass());
    FPM.add(createCFGSimplificationPass());
    FPM.add(createSROAPass());
    FPM.add(createEarlyCSEPass());
    FPM.add(createLowerExpectIntrinsicPass());

    FPM.doInitialization();
    for (Module::iterator I = mod.begin(),
           E = mod.end(); I != E; ++I)
      if (!I->isDeclaration())
        FPM.run(*I);
    FPM.doFinalization();
  }

  void runModulePass(Module &mod, TargetLibraryInfo *libraryInfo, int optLevel)
  {
    llvm::PassManager MPM;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    MPM.add(new DataLayoutPass(&mod));
#else
    MPM.add(new DataLayout(&mod));
#endif
    MPM.add(new TargetLibraryInfo(*libraryInfo));
    MPM.add(createTypeBasedAliasAnalysisPass());
    MPM.add(createBasicAliasAnalysisPass());
    MPM.add(createGlobalOptimizerPass());     // Optimize out global vars

    MPM.add(createIPSCCPPass());              // IP SCCP
    MPM.add(createDeadArgEliminationPass());  // Dead argument elimination

    MPM.add(createInstructionCombiningPass());// Clean up after IPCP & DAE
    MPM.add(createCFGSimplificationPass());   // Clean up after IPCP & DAE
    MPM.add(createPruneEHPass());             // Remove dead EH info
    MPM.add(createBarrierNodupPass(false));   // remove noduplicate fnAttr before inlining.
    MPM.add(createFunctionInliningPass(200000));
    MPM.add(createBarrierNodupPass(true));    // restore noduplicate fnAttr after inlining.
    MPM.add(createFunctionAttrsPass());       // Set readonly/readnone attrs

    //MPM.add(createScalarReplAggregatesPass(64, true, -1, -1, 64))
    if(optLevel > 0)
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
    MPM.add(createEarlyCSEPass());              // Catch trivial redundancies
    MPM.add(createJumpThreadingPass());         // Thread jumps.
    MPM.add(createCorrelatedValuePropagationPass()); // Propagate conditionals
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Combine silly seq's

    MPM.add(createTailCallEliminationPass());   // Eliminate tail calls
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createReassociatePass());           // Reassociate expressions
    MPM.add(createLoopRotatePass());            // Rotate Loop
    MPM.add(createLICMPass());                  // Hoist loop invariants
    MPM.add(createLoopUnswitchPass(true));
    MPM.add(createInstructionCombiningPass());
    MPM.add(createIndVarSimplifyPass());        // Canonicalize indvars
    MPM.add(createLoopIdiomPass());             // Recognize idioms like memset.
    MPM.add(createLoopDeletionPass());          // Delete dead loops
    MPM.add(createLoopUnrollPass());          // Unroll small loops
    if(optLevel > 0)
      MPM.add(createGVNPass());                 // Remove redundancies
    MPM.add(createMemCpyOptPass());             // Remove memcpy / form memset
    MPM.add(createSCCPPass());                  // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    MPM.add(createInstructionCombiningPass());
    MPM.add(createJumpThreadingPass());         // Thread jumps
    MPM.add(createCorrelatedValuePropagationPass());
    MPM.add(createDeadStoreEliminationPass());  // Delete dead stores
    MPM.add(createAggressiveDCEPass());         // Delete dead instructions
    MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Clean up after everything.
    MPM.add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
    if(optLevel > 0) {
      MPM.add(createGlobalDCEPass());         // Remove dead fns and globals.
      MPM.add(createConstantMergePass());     // Merge dup global constants
    }

    MPM.run(mod);
  }

  bool llvmToGen(ir::Unit &unit, const char *fileName,const void* module, int optLevel)
  {
    std::string errInfo;
    std::unique_ptr<llvm::raw_fd_ostream> o = NULL;
    if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS || OCL_OUTPUT_LLVM)
      o = std::unique_ptr<llvm::raw_fd_ostream>(new llvm::raw_fd_ostream(fileno(stdout), false));

    // Get the module from its file
    llvm::SMDiagnostic Err;
    std::auto_ptr<Module> M;
    if(fileName){
      // only when module is null, Get the global LLVM context
      llvm::LLVMContext& c = llvm::getGlobalContext();
      M.reset(ParseIRFile(fileName, Err, c));
      if (M.get() == 0) return false;
    }
    Module &mod = (module!=NULL)?*(llvm::Module*)module:*M.get();

    Triple TargetTriple(mod.getTargetTriple());
    TargetLibraryInfo *libraryInfo = new TargetLibraryInfo(TargetTriple);
    libraryInfo->disableAllFunctions();

    runFuntionPass(mod, libraryInfo);
    runModulePass(mod, libraryInfo, optLevel);

    llvm::PassManager passes;
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    passes.add(new DataLayoutPass(&mod));
#else
    passes.add(new DataLayout(&mod));
#endif
    // Print the code before further optimizations
    if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS)
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
      passes.add(createPrintModulePass(*o));
#else
      passes.add(createPrintModulePass(&*o));
#endif
    passes.add(createIntrinsicLoweringPass());
    passes.add(createFunctionInliningPass(200000));
    passes.add(createScalarReplAggregatesPass()); // Break up allocas
    passes.add(createLoadStoreOptimizationPass());
    passes.add(createRemoveGEPPass(unit));
    passes.add(createConstantPropagationPass());
    passes.add(createLowerSwitchPass());
    passes.add(createPromoteMemoryToRegisterPass());
    if(optLevel > 0)
      passes.add(createGVNPass());                  // Remove redundancies
    passes.add(createPrintfParserPass());
    passes.add(createScalarizePass());        // Expand all vector ops
    passes.add(createDeadInstEliminationPass());  // Remove simplified instructions
    passes.add(createCFGSimplificationPass());     // Merge & remove BBs
    passes.add(createScalarizePass());        // Expand all vector ops

    if(OCL_OUTPUT_CFG)
      passes.add(createCFGPrinterPass());
    if(OCL_OUTPUT_CFG_ONLY)
      passes.add(createCFGOnlyPrinterPass());
    passes.add(createGenPass(unit));

    // Print the code extra optimization passes
    if (OCL_OUTPUT_LLVM)
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
      passes.add(createPrintModulePass(*o));
#else
      passes.add(createPrintModulePass(&*o));
#endif
    passes.run(mod);

    return true;
  }
} /* namespace gbe */
<commit_msg>Enable structural analysis<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file llvm_to_gen.cpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */

#include "llvm/Config/llvm-config.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/DataLayout.h"
#else
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DataLayout.h"
#endif  /* LLVM_VERSION_MINOR <= 2 */
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/ADT/Triple.h"
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2
#include "llvm/Support/IRReader.h"
#else
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#endif  /* LLVM_VERSION_MINOR <= 2 */
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/Verifier.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#endif

#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/llvm_gen_backend.hpp"
#include "llvm/llvm_to_gen.hpp"
#include "sys/cvar.hpp"
#include "sys/platform.hpp"
#include "ir/unit.hpp"
#include "ir/structural_analysis.hpp"

#include <clang/CodeGen/CodeGenAction.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <memory>

namespace gbe
{
  BVAR(OCL_OUTPUT_LLVM, false);
  BVAR(OCL_OUTPUT_CFG, false);
  BVAR(OCL_OUTPUT_CFG_ONLY, false);
  BVAR(OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS, false);
  using namespace llvm;

  void runFuntionPass(Module &mod, TargetLibraryInfo *libraryInfo)
  {
    FunctionPassManager FPM(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    FPM.add(new DataLayoutPass(&mod));
#else
    FPM.add(new DataLayout(&mod));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
    FPM.add(createVerifierPass(true));
#else
    FPM.add(createVerifierPass());
#endif
    FPM.add(new TargetLibraryInfo(*libraryInfo));
    FPM.add(createTypeBasedAliasAnalysisPass());
    FPM.add(createBasicAliasAnalysisPass());
    FPM.add(createCFGSimplificationPass());
    FPM.add(createSROAPass());
    FPM.add(createEarlyCSEPass());
    FPM.add(createLowerExpectIntrinsicPass());

    FPM.doInitialization();
    for (Module::iterator I = mod.begin(),
           E = mod.end(); I != E; ++I)
      if (!I->isDeclaration())
        FPM.run(*I);
    FPM.doFinalization();
  }

  void runModulePass(Module &mod, TargetLibraryInfo *libraryInfo, int optLevel)
  {
    llvm::PassManager MPM;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    MPM.add(new DataLayoutPass(&mod));
#else
    MPM.add(new DataLayout(&mod));
#endif
    MPM.add(new TargetLibraryInfo(*libraryInfo));
    MPM.add(createTypeBasedAliasAnalysisPass());
    MPM.add(createBasicAliasAnalysisPass());
    MPM.add(createGlobalOptimizerPass());     // Optimize out global vars

    MPM.add(createIPSCCPPass());              // IP SCCP
    MPM.add(createDeadArgEliminationPass());  // Dead argument elimination

    MPM.add(createInstructionCombiningPass());// Clean up after IPCP & DAE
    MPM.add(createCFGSimplificationPass());   // Clean up after IPCP & DAE
    MPM.add(createPruneEHPass());             // Remove dead EH info
    MPM.add(createBarrierNodupPass(false));   // remove noduplicate fnAttr before inlining.
    MPM.add(createFunctionInliningPass(200000));
    MPM.add(createBarrierNodupPass(true));    // restore noduplicate fnAttr after inlining.
    MPM.add(createFunctionAttrsPass());       // Set readonly/readnone attrs

    //MPM.add(createScalarReplAggregatesPass(64, true, -1, -1, 64))
    if(optLevel > 0)
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
    MPM.add(createEarlyCSEPass());              // Catch trivial redundancies
    MPM.add(createJumpThreadingPass());         // Thread jumps.
    MPM.add(createCorrelatedValuePropagationPass()); // Propagate conditionals
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Combine silly seq's

    MPM.add(createTailCallEliminationPass());   // Eliminate tail calls
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createReassociatePass());           // Reassociate expressions
    MPM.add(createLoopRotatePass());            // Rotate Loop
    MPM.add(createLICMPass());                  // Hoist loop invariants
    MPM.add(createLoopUnswitchPass(true));
    MPM.add(createInstructionCombiningPass());
    MPM.add(createIndVarSimplifyPass());        // Canonicalize indvars
    MPM.add(createLoopIdiomPass());             // Recognize idioms like memset.
    MPM.add(createLoopDeletionPass());          // Delete dead loops
    MPM.add(createLoopUnrollPass());          // Unroll small loops
    if(optLevel > 0)
      MPM.add(createGVNPass());                 // Remove redundancies
    MPM.add(createMemCpyOptPass());             // Remove memcpy / form memset
    MPM.add(createSCCPPass());                  // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    MPM.add(createInstructionCombiningPass());
    MPM.add(createJumpThreadingPass());         // Thread jumps
    MPM.add(createCorrelatedValuePropagationPass());
    MPM.add(createDeadStoreEliminationPass());  // Delete dead stores
    MPM.add(createAggressiveDCEPass());         // Delete dead instructions
    MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Clean up after everything.
    MPM.add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
    if(optLevel > 0) {
      MPM.add(createGlobalDCEPass());         // Remove dead fns and globals.
      MPM.add(createConstantMergePass());     // Merge dup global constants
    }

    MPM.run(mod);
  }

  bool llvmToGen(ir::Unit &unit, const char *fileName,const void* module, int optLevel)
  {
    std::string errInfo;
    std::unique_ptr<llvm::raw_fd_ostream> o = NULL;
    if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS || OCL_OUTPUT_LLVM)
      o = std::unique_ptr<llvm::raw_fd_ostream>(new llvm::raw_fd_ostream(fileno(stdout), false));

    // Get the module from its file
    llvm::SMDiagnostic Err;
    std::auto_ptr<Module> M;
    if(fileName){
      // only when module is null, Get the global LLVM context
      llvm::LLVMContext& c = llvm::getGlobalContext();
      M.reset(ParseIRFile(fileName, Err, c));
      if (M.get() == 0) return false;
    }
    Module &mod = (module!=NULL)?*(llvm::Module*)module:*M.get();

    Triple TargetTriple(mod.getTargetTriple());
    TargetLibraryInfo *libraryInfo = new TargetLibraryInfo(TargetTriple);
    libraryInfo->disableAllFunctions();

    runFuntionPass(mod, libraryInfo);
    runModulePass(mod, libraryInfo, optLevel);

    llvm::PassManager passes;
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    passes.add(new DataLayoutPass(&mod));
#else
    passes.add(new DataLayout(&mod));
#endif
    // Print the code before further optimizations
    if (OCL_OUTPUT_LLVM_BEFORE_EXTRA_PASS)
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
      passes.add(createPrintModulePass(*o));
#else
      passes.add(createPrintModulePass(&*o));
#endif
    passes.add(createIntrinsicLoweringPass());
    passes.add(createFunctionInliningPass(200000));
    passes.add(createScalarReplAggregatesPass()); // Break up allocas
    passes.add(createLoadStoreOptimizationPass());
    passes.add(createRemoveGEPPass(unit));
    passes.add(createConstantPropagationPass());
    passes.add(createLowerSwitchPass());
    passes.add(createPromoteMemoryToRegisterPass());
    if(optLevel > 0)
      passes.add(createGVNPass());                  // Remove redundancies
    passes.add(createPrintfParserPass());
    passes.add(createScalarizePass());        // Expand all vector ops
    passes.add(createDeadInstEliminationPass());  // Remove simplified instructions
    passes.add(createCFGSimplificationPass());     // Merge & remove BBs
    passes.add(createScalarizePass());        // Expand all vector ops

    if(OCL_OUTPUT_CFG)
      passes.add(createCFGPrinterPass());
    if(OCL_OUTPUT_CFG_ONLY)
      passes.add(createCFGOnlyPrinterPass());
    passes.add(createGenPass(unit));

    // Print the code extra optimization passes
    if (OCL_OUTPUT_LLVM)
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
      passes.add(createPrintModulePass(*o));
#else
      passes.add(createPrintModulePass(&*o));
#endif
    passes.run(mod);

    const ir::Unit::FunctionSet& fs = unit.getFunctionSet();
    ir::Unit::FunctionSet::const_iterator iter = fs.begin();
    while(iter != fs.end())
    {
      analysis::ControlTree *ct = new analysis::ControlTree(iter->second);
      ct->analyze();
      delete ct;
      iter++;
    }

    return true;
  }
} /* namespace gbe */
<|endoftext|>


<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file llvm_to_gen.cpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */

#include "llvm_includes.hpp"

#include "llvm/llvm_gen_backend.hpp"
#include "llvm/llvm_to_gen.hpp"
#include "sys/cvar.hpp"
#include "sys/platform.hpp"
#include "ir/unit.hpp"
#include "ir/function.hpp"
#include "ir/structurizer.hpp"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <memory>

namespace gbe
{
  BVAR(OCL_OUTPUT_CFG, false);
  BVAR(OCL_OUTPUT_CFG_ONLY, false);
  BVAR(OCL_OUTPUT_CFG_GEN_IR, false);
  using namespace llvm;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
  using namespace llvm::legacy;
  #define TARGETLIBRARY  TargetLibraryInfoImpl
#else
  #define TARGETLIBRARY  TargetLibraryInfo
#endif

  void runFuntionPass(Module &mod, TARGETLIBRARY *libraryInfo, const DataLayout &DL)
  {
    FunctionPassManager FPM(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    FPM.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    FPM.add(new DataLayoutPass(DL));
#else
    FPM.add(new DataLayout(DL));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
    FPM.add(createVerifierPass(true));
#else
    FPM.add(createVerifierPass());
#endif
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    FPM.add(new TargetLibraryInfoWrapperPass(*libraryInfo));
#else
    FPM.add(new TargetLibraryInfo(*libraryInfo));
#endif
    FPM.add(createTypeBasedAliasAnalysisPass());
    FPM.add(createBasicAliasAnalysisPass());
    FPM.add(createCFGSimplificationPass());
    FPM.add(createSROAPass());
    FPM.add(createEarlyCSEPass());
    FPM.add(createLowerExpectIntrinsicPass());

    FPM.doInitialization();
    for (Module::iterator I = mod.begin(),
           E = mod.end(); I != E; ++I)
      if (!I->isDeclaration())
        FPM.run(*I);
    FPM.doFinalization();
  }

  void runModulePass(Module &mod, TARGETLIBRARY *libraryInfo, const DataLayout &DL, int optLevel, bool strictMath)
  {
    PassManager MPM;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    MPM.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    MPM.add(new DataLayoutPass(DL));
#else
    MPM.add(new DataLayout(DL));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    MPM.add(new TargetLibraryInfoWrapperPass(*libraryInfo));
#else
    MPM.add(new TargetLibraryInfo(*libraryInfo));
#endif
    MPM.add(createTypeBasedAliasAnalysisPass());
    MPM.add(createBasicAliasAnalysisPass());
    MPM.add(createIntrinsicLoweringPass());
    MPM.add(createStripAttributesPass());     // Strip unsupported attributes and calling conventions.
    MPM.add(createSamplerFixPass());
    MPM.add(createGlobalOptimizerPass());     // Optimize out global vars

    MPM.add(createIPSCCPPass());              // IP SCCP
    MPM.add(createDeadArgEliminationPass());  // Dead argument elimination

    MPM.add(createInstructionCombiningPass());// Clean up after IPCP & DAE
    MPM.add(createCFGSimplificationPass());   // Clean up after IPCP & DAE
    MPM.add(createPruneEHPass());             // Remove dead EH info
    MPM.add(createBarrierNodupPass(false));   // remove noduplicate fnAttr before inlining.
    MPM.add(createFunctionInliningPass(20000));
    MPM.add(createBarrierNodupPass(true));    // restore noduplicate fnAttr after inlining.
    MPM.add(createFunctionAttrsPass());       // Set readonly/readnone attrs

    //MPM.add(createScalarReplAggregatesPass(64, true, -1, -1, 64))
    if(optLevel > 0)
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
    MPM.add(createEarlyCSEPass());              // Catch trivial redundancies
    MPM.add(createJumpThreadingPass());         // Thread jumps.
    MPM.add(createCorrelatedValuePropagationPass()); // Propagate conditionals
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Combine silly seq's

    MPM.add(createTailCallEliminationPass());   // Eliminate tail calls
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createReassociatePass());           // Reassociate expressions
    MPM.add(createLoopRotatePass());            // Rotate Loop
    MPM.add(createLICMPass());                  // Hoist loop invariants
    MPM.add(createLoopUnswitchPass(true));
    MPM.add(createInstructionCombiningPass());
    MPM.add(createIndVarSimplifyPass());        // Canonicalize indvars
    MPM.add(createLoopIdiomPass());             // Recognize idioms like memset.
    MPM.add(createLoopDeletionPass());          // Delete dead loops
    MPM.add(createLoopUnrollPass(1024)); //1024, 32, 1024, 512)); //Unroll loops
    if(optLevel > 0) {
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
      MPM.add(createGVNPass());                 // Remove redundancies
    }
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    // FIXME Workaround: we find that CustomLoopUnroll may increase register pressure greatly,
    // and it may even make som cl kernel cannot compile because of limited scratch memory for spill.
    // As we observe this under strict math. So we disable CustomLoopUnroll if strict math is enabled.
    if (!strictMath) {
      MPM.add(createCustomLoopUnrollPass()); //1024, 32, 1024, 512)); //Unroll loops
      MPM.add(createLoopUnrollPass()); //1024, 32, 1024, 512)); //Unroll loops
      if(optLevel > 0) {
        MPM.add(createSROAPass(/*RequiresDomTree*/ false));
        MPM.add(createGVNPass());                 // Remove redundancies
      }
    }
#endif
    MPM.add(createMemCpyOptPass());             // Remove memcpy / form memset
    MPM.add(createSCCPPass());                  // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    MPM.add(createInstructionCombiningPass());
    MPM.add(createJumpThreadingPass());         // Thread jumps
    MPM.add(createCorrelatedValuePropagationPass());
    MPM.add(createDeadStoreEliminationPass());  // Delete dead stores
    MPM.add(createAggressiveDCEPass());         // Delete dead instructions
    MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Clean up after everything.
    MPM.add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
    if(optLevel > 0) {
      MPM.add(createGlobalDCEPass());         // Remove dead fns and globals.
      MPM.add(createConstantMergePass());     // Merge dup global constants
    }

    MPM.run(mod);
  }

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
#define OUTPUT_BITCODE(STAGE, MOD)  do {         \
   PassManager passes__;           \
   if (OCL_OUTPUT_LLVM_##STAGE) {                \
     passes__.add(createPrintModulePass(*o));    \
     passes__.run(MOD);                          \
   }                                             \
 }while(0)
#else
#define OUTPUT_BITCODE(STAGE, MOD)  do {         \
   PassManager passes__;           \
   if (OCL_OUTPUT_LLVM_##STAGE) {                \
     passes__.add(createPrintModulePass(&*o));   \
     passes__.run(MOD);                          \
   }                                             \
 }while(0)
#endif

  BVAR(OCL_OUTPUT_LLVM_BEFORE_LINK, false);
  BVAR(OCL_OUTPUT_LLVM_AFTER_LINK, false);
  BVAR(OCL_OUTPUT_LLVM_AFTER_GEN, false);

  bool llvmToGen(ir::Unit &unit, const char *fileName,const void* module,
                 int optLevel, bool strictMath, int profiling)
  {
    std::string errInfo;
    std::unique_ptr<llvm::raw_fd_ostream> o = NULL;
    if (OCL_OUTPUT_LLVM_BEFORE_LINK || OCL_OUTPUT_LLVM_AFTER_LINK || OCL_OUTPUT_LLVM_AFTER_GEN)
      o = std::unique_ptr<llvm::raw_fd_ostream>(new llvm::raw_fd_ostream(fileno(stdout), false));

    // Get the module from its file
    llvm::SMDiagnostic Err;

    Module* cl_mod = NULL;
    if (module) {
      cl_mod = reinterpret_cast<Module*>(const_cast<void*>(module));
    } else if (fileName){
      llvm::LLVMContext& c = llvm::getGlobalContext();
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
      cl_mod = parseIRFile(fileName, Err, c).release();
#else
      cl_mod = ParseIRFile(fileName, Err, c);
#endif
    }

    if (!cl_mod) return false;

    OUTPUT_BITCODE(BEFORE_LINK, (*cl_mod));

    std::unique_ptr<Module> M;

    /* Before do any thing, we first filter in all CL functions in bitcode. */
    M.reset(runBitCodeLinker(cl_mod, strictMath));
    if (!module)
      delete cl_mod;
    if (M.get() == 0)
      return true;

    Module &mod = *M.get();
    DataLayout DL(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    mod.setDataLayout(DL);
#endif
    Triple TargetTriple(mod.getTargetTriple());
    TARGETLIBRARY *libraryInfo = new TARGETLIBRARY(TargetTriple);
    libraryInfo->disableAllFunctions();

    OUTPUT_BITCODE(AFTER_LINK, mod);

    runFuntionPass(mod, libraryInfo, DL);
    runModulePass(mod, libraryInfo, DL, optLevel, strictMath);
    PassManager passes;
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    passes.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    passes.add(new DataLayoutPass(DL));
#else
    passes.add(new DataLayout(DL));
#endif
    // Print the code before further optimizations
    passes.add(createIntrinsicLoweringPass());
    passes.add(createStripAttributesPass());     // Strip unsupported attributes and calling conventions.
    passes.add(createFunctionInliningPass(20000));
    passes.add(createScalarReplAggregatesPass(64, true, -1, -1, 64));
    passes.add(createLoadStoreOptimizationPass());
    passes.add(createConstantPropagationPass());
    passes.add(createPromoteMemoryToRegisterPass());
    if(optLevel > 0)
      passes.add(createGVNPass());                 // Remove redundancies
    passes.add(createPrintfParserPass());
    passes.add(createExpandConstantExprPass());    // expand ConstantExpr
    passes.add(createScalarizePass());             // Expand all vector ops
    passes.add(createExpandLargeIntegersPass());   // legalize large integer operation
    passes.add(createInstructionCombiningPass());  // legalize will generate some silly instructions
    passes.add(createConstantPropagationPass());   // propagate constant after scalarize/legalize
    passes.add(createExpandConstantExprPass());    // constant prop may generate ConstantExpr
    passes.add(createPromoteIntegersPass());       // align integer size to power of two
    passes.add(createRemoveGEPPass(unit));         // Constant prop may generate gep
    passes.add(createDeadInstEliminationPass());   // Remove simplified instructions
    passes.add(createCFGSimplificationPass());     // Merge & remove BBs
    passes.add(createLowerSwitchPass());           // simplify cfg will generate switch-case instruction
    if (profiling) {
      passes.add(createProfilingInserterPass(profiling, unit));     // insert the time stamp for profiling.
    }
    passes.add(createScalarizePass());             // Expand all vector ops

    if(OCL_OUTPUT_CFG)
      passes.add(createCFGPrinterPass());
    if(OCL_OUTPUT_CFG_ONLY)
      passes.add(createCFGOnlyPrinterPass());
    passes.add(createGenPass(unit));
    passes.run(mod);

    // Print the code extra optimization passes
    OUTPUT_BITCODE(AFTER_GEN, mod);

    const ir::Unit::FunctionSet& fs = unit.getFunctionSet();
    ir::Unit::FunctionSet::const_iterator iter = fs.begin();
    while(iter != fs.end())
    {
      ir::CFGStructurizer *structurizer = new ir::CFGStructurizer(iter->second);
      structurizer->StructurizeBlocks();
      delete structurizer;
      if (OCL_OUTPUT_CFG_GEN_IR)
        iter->second->outputCFG();
      iter++;
    }

    delete libraryInfo;
    return true;
  }
} /* namespace gbe */
<commit_msg>GBE: decrease the loop unrolling threshold to 640.<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file llvm_to_gen.cpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */

#include "llvm_includes.hpp"

#include "llvm/llvm_gen_backend.hpp"
#include "llvm/llvm_to_gen.hpp"
#include "sys/cvar.hpp"
#include "sys/platform.hpp"
#include "ir/unit.hpp"
#include "ir/function.hpp"
#include "ir/structurizer.hpp"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <memory>

namespace gbe
{
  BVAR(OCL_OUTPUT_CFG, false);
  BVAR(OCL_OUTPUT_CFG_ONLY, false);
  BVAR(OCL_OUTPUT_CFG_GEN_IR, false);
  using namespace llvm;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
  using namespace llvm::legacy;
  #define TARGETLIBRARY  TargetLibraryInfoImpl
#else
  #define TARGETLIBRARY  TargetLibraryInfo
#endif

  void runFuntionPass(Module &mod, TARGETLIBRARY *libraryInfo, const DataLayout &DL)
  {
    FunctionPassManager FPM(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    FPM.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    FPM.add(new DataLayoutPass(DL));
#else
    FPM.add(new DataLayout(DL));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >=5
    FPM.add(createVerifierPass(true));
#else
    FPM.add(createVerifierPass());
#endif
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    FPM.add(new TargetLibraryInfoWrapperPass(*libraryInfo));
#else
    FPM.add(new TargetLibraryInfo(*libraryInfo));
#endif
    FPM.add(createTypeBasedAliasAnalysisPass());
    FPM.add(createBasicAliasAnalysisPass());
    FPM.add(createCFGSimplificationPass());
    FPM.add(createSROAPass());
    FPM.add(createEarlyCSEPass());
    FPM.add(createLowerExpectIntrinsicPass());

    FPM.doInitialization();
    for (Module::iterator I = mod.begin(),
           E = mod.end(); I != E; ++I)
      if (!I->isDeclaration())
        FPM.run(*I);
    FPM.doFinalization();
  }

  void runModulePass(Module &mod, TARGETLIBRARY *libraryInfo, const DataLayout &DL, int optLevel, bool strictMath)
  {
    PassManager MPM;

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    MPM.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    MPM.add(new DataLayoutPass(DL));
#else
    MPM.add(new DataLayout(DL));
#endif

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    MPM.add(new TargetLibraryInfoWrapperPass(*libraryInfo));
#else
    MPM.add(new TargetLibraryInfo(*libraryInfo));
#endif
    MPM.add(createTypeBasedAliasAnalysisPass());
    MPM.add(createBasicAliasAnalysisPass());
    MPM.add(createIntrinsicLoweringPass());
    MPM.add(createStripAttributesPass());     // Strip unsupported attributes and calling conventions.
    MPM.add(createSamplerFixPass());
    MPM.add(createGlobalOptimizerPass());     // Optimize out global vars

    MPM.add(createIPSCCPPass());              // IP SCCP
    MPM.add(createDeadArgEliminationPass());  // Dead argument elimination

    MPM.add(createInstructionCombiningPass());// Clean up after IPCP & DAE
    MPM.add(createCFGSimplificationPass());   // Clean up after IPCP & DAE
    MPM.add(createPruneEHPass());             // Remove dead EH info
    MPM.add(createBarrierNodupPass(false));   // remove noduplicate fnAttr before inlining.
    MPM.add(createFunctionInliningPass(20000));
    MPM.add(createBarrierNodupPass(true));    // restore noduplicate fnAttr after inlining.
    MPM.add(createFunctionAttrsPass());       // Set readonly/readnone attrs

    //MPM.add(createScalarReplAggregatesPass(64, true, -1, -1, 64))
    if(optLevel > 0)
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
    MPM.add(createEarlyCSEPass());              // Catch trivial redundancies
    MPM.add(createJumpThreadingPass());         // Thread jumps.
    MPM.add(createCorrelatedValuePropagationPass()); // Propagate conditionals
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Combine silly seq's

    MPM.add(createTailCallEliminationPass());   // Eliminate tail calls
    MPM.add(createCFGSimplificationPass());     // Merge & remove BBs
    MPM.add(createReassociatePass());           // Reassociate expressions
    MPM.add(createLoopRotatePass());            // Rotate Loop
    MPM.add(createLICMPass());                  // Hoist loop invariants
    MPM.add(createLoopUnswitchPass(true));
    MPM.add(createInstructionCombiningPass());
    MPM.add(createIndVarSimplifyPass());        // Canonicalize indvars
    MPM.add(createLoopIdiomPass());             // Recognize idioms like memset.
    MPM.add(createLoopDeletionPass());          // Delete dead loops
    MPM.add(createLoopUnrollPass(640)); //1024, 32, 1024, 512)); //Unroll loops
    if(optLevel > 0) {
      MPM.add(createSROAPass(/*RequiresDomTree*/ false));
      MPM.add(createGVNPass());                 // Remove redundancies
    }
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
    // FIXME Workaround: we find that CustomLoopUnroll may increase register pressure greatly,
    // and it may even make som cl kernel cannot compile because of limited scratch memory for spill.
    // As we observe this under strict math. So we disable CustomLoopUnroll if strict math is enabled.
    if (!strictMath) {
      MPM.add(createCustomLoopUnrollPass()); //1024, 32, 1024, 512)); //Unroll loops
      MPM.add(createLoopUnrollPass()); //1024, 32, 1024, 512)); //Unroll loops
      if(optLevel > 0) {
        MPM.add(createSROAPass(/*RequiresDomTree*/ false));
        MPM.add(createGVNPass());                 // Remove redundancies
      }
    }
#endif
    MPM.add(createMemCpyOptPass());             // Remove memcpy / form memset
    MPM.add(createSCCPPass());                  // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    MPM.add(createInstructionCombiningPass());
    MPM.add(createJumpThreadingPass());         // Thread jumps
    MPM.add(createCorrelatedValuePropagationPass());
    MPM.add(createDeadStoreEliminationPass());  // Delete dead stores
    MPM.add(createAggressiveDCEPass());         // Delete dead instructions
    MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
    MPM.add(createInstructionCombiningPass());  // Clean up after everything.
    MPM.add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
    if(optLevel > 0) {
      MPM.add(createGlobalDCEPass());         // Remove dead fns and globals.
      MPM.add(createConstantMergePass());     // Merge dup global constants
    }

    MPM.run(mod);
  }

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5
#define OUTPUT_BITCODE(STAGE, MOD)  do {         \
   PassManager passes__;           \
   if (OCL_OUTPUT_LLVM_##STAGE) {                \
     passes__.add(createPrintModulePass(*o));    \
     passes__.run(MOD);                          \
   }                                             \
 }while(0)
#else
#define OUTPUT_BITCODE(STAGE, MOD)  do {         \
   PassManager passes__;           \
   if (OCL_OUTPUT_LLVM_##STAGE) {                \
     passes__.add(createPrintModulePass(&*o));   \
     passes__.run(MOD);                          \
   }                                             \
 }while(0)
#endif

  BVAR(OCL_OUTPUT_LLVM_BEFORE_LINK, false);
  BVAR(OCL_OUTPUT_LLVM_AFTER_LINK, false);
  BVAR(OCL_OUTPUT_LLVM_AFTER_GEN, false);

  bool llvmToGen(ir::Unit &unit, const char *fileName,const void* module,
                 int optLevel, bool strictMath, int profiling)
  {
    std::string errInfo;
    std::unique_ptr<llvm::raw_fd_ostream> o = NULL;
    if (OCL_OUTPUT_LLVM_BEFORE_LINK || OCL_OUTPUT_LLVM_AFTER_LINK || OCL_OUTPUT_LLVM_AFTER_GEN)
      o = std::unique_ptr<llvm::raw_fd_ostream>(new llvm::raw_fd_ostream(fileno(stdout), false));

    // Get the module from its file
    llvm::SMDiagnostic Err;

    Module* cl_mod = NULL;
    if (module) {
      cl_mod = reinterpret_cast<Module*>(const_cast<void*>(module));
    } else if (fileName){
      llvm::LLVMContext& c = llvm::getGlobalContext();
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
      cl_mod = parseIRFile(fileName, Err, c).release();
#else
      cl_mod = ParseIRFile(fileName, Err, c);
#endif
    }

    if (!cl_mod) return false;

    OUTPUT_BITCODE(BEFORE_LINK, (*cl_mod));

    std::unique_ptr<Module> M;

    /* Before do any thing, we first filter in all CL functions in bitcode. */
    M.reset(runBitCodeLinker(cl_mod, strictMath));
    if (!module)
      delete cl_mod;
    if (M.get() == 0)
      return true;

    Module &mod = *M.get();
    DataLayout DL(&mod);

#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
    mod.setDataLayout(DL);
#endif
    Triple TargetTriple(mod.getTargetTriple());
    TARGETLIBRARY *libraryInfo = new TARGETLIBRARY(TargetTriple);
    libraryInfo->disableAllFunctions();

    OUTPUT_BITCODE(AFTER_LINK, mod);

    runFuntionPass(mod, libraryInfo, DL);
    runModulePass(mod, libraryInfo, DL, optLevel, strictMath);
    PassManager passes;
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 6
    passes.add(new DataLayoutPass());
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
    passes.add(new DataLayoutPass(DL));
#else
    passes.add(new DataLayout(DL));
#endif
    // Print the code before further optimizations
    passes.add(createIntrinsicLoweringPass());
    passes.add(createStripAttributesPass());     // Strip unsupported attributes and calling conventions.
    passes.add(createFunctionInliningPass(20000));
    passes.add(createScalarReplAggregatesPass(64, true, -1, -1, 64));
    passes.add(createLoadStoreOptimizationPass());
    passes.add(createConstantPropagationPass());
    passes.add(createPromoteMemoryToRegisterPass());
    if(optLevel > 0)
      passes.add(createGVNPass());                 // Remove redundancies
    passes.add(createPrintfParserPass());
    passes.add(createExpandConstantExprPass());    // expand ConstantExpr
    passes.add(createScalarizePass());             // Expand all vector ops
    passes.add(createExpandLargeIntegersPass());   // legalize large integer operation
    passes.add(createInstructionCombiningPass());  // legalize will generate some silly instructions
    passes.add(createConstantPropagationPass());   // propagate constant after scalarize/legalize
    passes.add(createExpandConstantExprPass());    // constant prop may generate ConstantExpr
    passes.add(createPromoteIntegersPass());       // align integer size to power of two
    passes.add(createRemoveGEPPass(unit));         // Constant prop may generate gep
    passes.add(createDeadInstEliminationPass());   // Remove simplified instructions
    passes.add(createCFGSimplificationPass());     // Merge & remove BBs
    passes.add(createLowerSwitchPass());           // simplify cfg will generate switch-case instruction
    if (profiling) {
      passes.add(createProfilingInserterPass(profiling, unit));     // insert the time stamp for profiling.
    }
    passes.add(createScalarizePass());             // Expand all vector ops

    if(OCL_OUTPUT_CFG)
      passes.add(createCFGPrinterPass());
    if(OCL_OUTPUT_CFG_ONLY)
      passes.add(createCFGOnlyPrinterPass());
    passes.add(createGenPass(unit));
    passes.run(mod);

    // Print the code extra optimization passes
    OUTPUT_BITCODE(AFTER_GEN, mod);

    const ir::Unit::FunctionSet& fs = unit.getFunctionSet();
    ir::Unit::FunctionSet::const_iterator iter = fs.begin();
    while(iter != fs.end())
    {
      ir::CFGStructurizer *structurizer = new ir::CFGStructurizer(iter->second);
      structurizer->StructurizeBlocks();
      delete structurizer;
      if (OCL_OUTPUT_CFG_GEN_IR)
        iter->second->outputCFG();
      iter++;
    }

    delete libraryInfo;
    return true;
  }
} /* namespace gbe */
<|endoftext|>


<commit_before>#ifndef __STRESS_CLIENT_PROTOCOL_HPP__
#define __STRESS_CLIENT_PROTOCOL_HPP__

#include <exception>
#include <string>
#include "distr.hpp"

class protocol_error_t : public std::exception, public std::string {
public:
    protocol_error_t(const std::string& message) : std::string(message) { }
    virtual ~protocol_error_t() throw () { }
};

struct protocol_t {
    virtual ~protocol_t() {}

    virtual void remove(const char *key, size_t key_size) = 0;
    virtual void update(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;
    virtual void insert(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;

    virtual void read(payload_t *keys, int count, payload_t *values = NULL) = 0;

    /* These functions allow reads to be pipelined to the server meaning there
     * will be several reads sent over the socket and the client will not block
     * on their return. It is the users job to make sure the queue doesn't get
     * bigger than they want it to. */

    /* By default these functions are just stubbed out in terms of read which
     * is sementically correct but offers no performance improvements. */

    /* add a read to the pipeline */
public:
    virtual void enqueue_read(payload_t *keys, int count, payload_t *values = NULL) {
        read(keys, count, values);
    }

    /* remove as many reads as have been returned from the pipeline */
    virtual bool dequeue_read_maybe(payload_t *keys, int count, payload_t *values = NULL) {
        return true;
    }

    /* Wait until all of the pipelined reads have been returned */
    virtual void dequeue_read(payload_t *keys, int count, payload_t *values = NULL) { }

    virtual void range_read(char* lkey, size_t lkey_size, char* rkey, size_t rkey_size, int count_limit, payload_t *values = NULL) = 0;

    virtual void append(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;

    virtual void prepend(const char *key, size_t key_size,
                          const char *value, size_t value_size) = 0;
};

#define MAX_HOST 255

enum protocol_enum_t {
    protocol_rethinkdb,
    protocol_sockmemcached,
#ifdef USE_MYSQL
    protocol_mysql,
#endif
#ifdef USE_LIBMEMCACHED
    protocol_libmemcached,
#endif
    protocol_sqlite,
};

struct server_t {
    server_t() : protocol(protocol_rethinkdb) {
        strcpy(host, "localhost:12346");
    }

    protocol_enum_t parse_protocol(const char *name) {
        if (strcmp(name, "rethinkdb") == 0) {
            return protocol_rethinkdb;
        } else if (strcmp(name, "sockmemcached") == 0) {
            return protocol_sockmemcached;
#ifdef USE_MYSQL
        } else if (strcmp(name, "mysql") == 0) {
            return protocol_mysql;
#endif
#ifdef USE_LIBMEMCACHED
        } else if (strcmp(name, "libmemcached") == 0) {
            return protocol_libmemcached;
#endif
        } else if(strcmp(name, "sqlite") == 0) {
            return protocol_sqlite;
        } else {
            fprintf(stderr, "Unknown protocol\n");
            exit(-1);
        }
    }

    void parse(const char *const_str) {
        char str[500];
        strncpy(str, const_str, sizeof(str));
        char *_host = NULL;
        if (_host = strchr(str, ',')) {
            *_host = '\0';
            _host++;
            protocol = parse_protocol(str);
        } else {
            _host = str;
            protocol = protocol_rethinkdb;
        }
        strncpy(host, _host, MAX_HOST);
    }

    void print_protocol() {
        if (protocol == protocol_rethinkdb) {
            printf("rethinkdb");
        } if (protocol == protocol_sockmemcached) {
            printf("sockmemcached");
#ifdef USE_MYSQL
        } else if (protocol == protocol_mysql) {
            printf("mysql");
#endif
#ifdef USE_LIBMEMCACHED
        } else if (protocol == protocol_libmemcached) {
            printf("libmemcached");
#endif
        } else if (protocol == protocol_sqlite) {
            printf("sqlite");
        } else {
            printf("unknown");
        }
    }

    void print() {
        print_protocol();
        printf(",%s", host);
    }

    protocol_t *connect();

    protocol_enum_t protocol;
    char host[MAX_HOST];
};

#endif // __STRESS_CLIENT_PROTOCOL_HPP__

<commit_msg>Forgot an else before an if.<commit_after>#ifndef __STRESS_CLIENT_PROTOCOL_HPP__
#define __STRESS_CLIENT_PROTOCOL_HPP__

#include <exception>
#include <string>
#include "distr.hpp"

class protocol_error_t : public std::exception, public std::string {
public:
    protocol_error_t(const std::string& message) : std::string(message) { }
    virtual ~protocol_error_t() throw () { }
};

struct protocol_t {
    virtual ~protocol_t() {}

    virtual void remove(const char *key, size_t key_size) = 0;
    virtual void update(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;
    virtual void insert(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;

    virtual void read(payload_t *keys, int count, payload_t *values = NULL) = 0;

    /* These functions allow reads to be pipelined to the server meaning there
     * will be several reads sent over the socket and the client will not block
     * on their return. It is the users job to make sure the queue doesn't get
     * bigger than they want it to. */

    /* By default these functions are just stubbed out in terms of read which
     * is sementically correct but offers no performance improvements. */

    /* add a read to the pipeline */
public:
    virtual void enqueue_read(payload_t *keys, int count, payload_t *values = NULL) {
        read(keys, count, values);
    }

    /* remove as many reads as have been returned from the pipeline */
    virtual bool dequeue_read_maybe(payload_t *keys, int count, payload_t *values = NULL) {
        return true;
    }

    /* Wait until all of the pipelined reads have been returned */
    virtual void dequeue_read(payload_t *keys, int count, payload_t *values = NULL) { }

    virtual void range_read(char* lkey, size_t lkey_size, char* rkey, size_t rkey_size, int count_limit, payload_t *values = NULL) = 0;

    virtual void append(const char *key, size_t key_size,
                        const char *value, size_t value_size) = 0;

    virtual void prepend(const char *key, size_t key_size,
                          const char *value, size_t value_size) = 0;
};

#define MAX_HOST 255

enum protocol_enum_t {
    protocol_rethinkdb,
    protocol_sockmemcached,
#ifdef USE_MYSQL
    protocol_mysql,
#endif
#ifdef USE_LIBMEMCACHED
    protocol_libmemcached,
#endif
    protocol_sqlite,
};

struct server_t {
    server_t() : protocol(protocol_rethinkdb) {
        strcpy(host, "localhost:12346");
    }

    protocol_enum_t parse_protocol(const char *name) {
        if (strcmp(name, "rethinkdb") == 0) {
            return protocol_rethinkdb;
        } else if (strcmp(name, "sockmemcached") == 0) {
            return protocol_sockmemcached;
#ifdef USE_MYSQL
        } else if (strcmp(name, "mysql") == 0) {
            return protocol_mysql;
#endif
#ifdef USE_LIBMEMCACHED
        } else if (strcmp(name, "libmemcached") == 0) {
            return protocol_libmemcached;
#endif
        } else if(strcmp(name, "sqlite") == 0) {
            return protocol_sqlite;
        } else {
            fprintf(stderr, "Unknown protocol\n");
            exit(-1);
        }
    }

    void parse(const char *const_str) {
        char str[500];
        strncpy(str, const_str, sizeof(str));
        char *_host = NULL;
        if (_host = strchr(str, ',')) {
            *_host = '\0';
            _host++;
            protocol = parse_protocol(str);
        } else {
            _host = str;
            protocol = protocol_rethinkdb;
        }
        strncpy(host, _host, MAX_HOST);
    }

    void print_protocol() {
        if (protocol == protocol_rethinkdb) {
            printf("rethinkdb");
        } else if (protocol == protocol_sockmemcached) {
            printf("sockmemcached");
#ifdef USE_MYSQL
        } else if (protocol == protocol_mysql) {
            printf("mysql");
#endif
#ifdef USE_LIBMEMCACHED
        } else if (protocol == protocol_libmemcached) {
            printf("libmemcached");
#endif
        } else if (protocol == protocol_sqlite) {
            printf("sqlite");
        } else {
            printf("unknown");
        }
    }

    void print() {
        print_protocol();
        printf(",%s", host);
    }

    protocol_t *connect();

    protocol_enum_t protocol;
    char host[MAX_HOST];
};

#endif // __STRESS_CLIENT_PROTOCOL_HPP__

<|endoftext|>


<commit_before>#include <celero/Celero.h>

#include <annis/query.h>
#include <annis/annosearch/exactannokeysearch.h>
#include <annis/annosearch/exactannovaluesearch.h>
#include <annis/annosearch/regexannosearch.h>

#include <annis/operators/pointing.h>
#include <annis/operators/precedence.h>

#ifdef ENABLE_VALGRIND
  #include <valgrind/callgrind.h>
#else
  #define CALLGRIND_STOP_INSTRUMENTATION

  #define CALLGRIND_START_INSTRUMENTATION
#endif // ENABLE_VALGRIND

using namespace annis;

int main(int argc, char** argv) {
  try
  {
    celero::Run(argc, argv);
    return 0;
  }
  catch(std::string ex)
  {
    std::cerr << "ERROR: " << ex << std::endl;
  }
  catch(char const* ex)
  {
    std::cerr << "ERROR: " << ex << std::endl;
  }
  catch(...)
  {
    std::cerr << "Some exception was thrown!" << std::endl;
  }

  return -1;
}

class GUMFixture : public celero::TestFixture
{
    public:
        GUMFixture()
          : count_PosDepPos(246), count_UsedTo(1)
        {
        }

        /*
        virtual std::vector<std::pair<int64_t, uint64_t>> getExperimentValues() const override
        {
            std::vector<std::pair<int64_t, uint64_t>> problemSpace;

            for(int64_t i=1; i <= std::thread::hardware_concurrency(); i++)
            {
              problemSpace.push_back(std::make_pair(i, uint64_t(0)));
            }
            return problemSpace;
        }
        */

        /// Before each run, build a vector of random integers.
        virtual void setUp(int64_t experimentValue)
        {
          CALLGRIND_STOP_INSTRUMENTATION;
          char* testDataEnv = std::getenv("ANNIS4_TEST_DATA");
          std::string dataDir("data");
          if (testDataEnv != NULL) {
            dataDir = testDataEnv;
          }
          db.load(dataDir + "/GUM", true);

          nonParallelConfig.numOfBackgroundTasks = 0;
          nonParallelConfig.threadPool = nullptr;

          static std::shared_ptr<ThreadPool> globalThreadPool = std::make_shared<ThreadPool>(128);

          taskConfigs.resize(9);
          threadConfigs.resize(9);

          for(int64_t i=1; i <= 8; i++)
          {
            QueryConfig taskCfg;
            taskCfg.threadPool = std::make_shared<ThreadPool>(i);
            taskCfg.numOfBackgroundTasks = 0;

            QueryConfig threadCfg;
            threadCfg.threadPool = globalThreadPool; // std::make_shared<ThreadPool>(i);
            threadCfg.numOfBackgroundTasks = i;

            taskConfigs[i] = taskCfg;
            threadConfigs[i] = threadCfg;
          }
        }

        std::shared_ptr<Query> query_PosDepPos(QueryConfig config)
        {
          std::shared_ptr<Query> result = std::make_shared<Query>(db, config);

          result->addNode(std::make_shared<ExactAnnoKeySearch>(db, "pos"));
          result->addNode(std::make_shared<ExactAnnoKeySearch>(db, "pos"));

          Annotation edgeAnno = {db.strings.add("func"), 0, db.strings.add("dep")};
          result->addOperator(std::make_shared<Pointing>(db.edges, db.strings, "", "dep", edgeAnno), 0, 1);

          return result;
        }

        std::shared_ptr<Query> query_UsedTo(QueryConfig config)
        {
          std::shared_ptr<Query> result = std::make_shared<Query>(db, config);

          result->addNode(std::make_shared<RegexAnnoSearch>(db, "pos", "NN.*"));
          result->addNode(std::make_shared<ExactAnnoValueSearch>(db, "annis4_internal", "tok", "used"));
          result->addNode(std::make_shared<ExactAnnoValueSearch>(db, "annis4_internal", "tok", "to"));

          result->addOperator(std::make_shared<Precedence>(db, db.edges), 0, 1);
          result->addOperator(std::make_shared<Precedence>(db, db.edges), 1, 2);
          return result;
        }

        DB db;
        QueryConfig nonParallelConfig;
        std::vector<QueryConfig> threadConfigs;
        std::vector<QueryConfig> taskConfigs;

        const int count_PosDepPos;
        const int count_UsedTo;

};

BASELINE_F(PosDepPos, NonParallel, GUMFixture, 0, 0)
{
  CALLGRIND_START_INSTRUMENTATION;
  std::shared_ptr<Query> q = query_PosDepPos(nonParallelConfig);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_PosDepPos)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_PosDepPos);
  }
  CALLGRIND_STOP_INSTRUMENTATION;
}

BASELINE_F(UsedTo, NonParallel, GUMFixture, 0, 0)
{
  CALLGRIND_START_INSTRUMENTATION;
  std::shared_ptr<Query> q = query_UsedTo(nonParallelConfig);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_UsedTo)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_UsedTo);
  }
  CALLGRIND_STOP_INSTRUMENTATION;
}

#define COUNT_BENCH(group, idx) \
  BENCHMARK_F(group, Thread_##idx, GUMFixture, 0, 0) \
  { \
  CALLGRIND_START_INSTRUMENTATION;\
    std::shared_ptr<Query> q = query_##group(threadConfigs[idx]);\
    int counter=0; \
    while(q->next()) { \
      counter++; \
    } \
    if(counter != count_##group)\
    {\
      throw "Invalid count for Thread_" #idx ", was " + std::to_string(counter) + " but should have been  " + std::to_string(count_##group);\
    }\
  CALLGRIND_STOP_INSTRUMENTATION;\
  } \
  BENCHMARK_F(group, Task_##idx, GUMFixture, 0, 0) \
  { \
    std::shared_ptr<Query> q = query_##group(taskConfigs[idx]);\
    int counter=0; \
    while(q->next()) { \
      counter++; \
    } \
    if(counter != count_##group)\
    {\
      throw "Invalid count for Task_" #idx ", was " + std::to_string(counter) + " but should have been  " + std::to_string(count_##group);\
    }\
  }

COUNT_BENCH(PosDepPos, 1)
COUNT_BENCH(PosDepPos, 2)
COUNT_BENCH(PosDepPos, 3)
COUNT_BENCH(PosDepPos, 4)
COUNT_BENCH(PosDepPos, 5)
COUNT_BENCH(PosDepPos, 6)
COUNT_BENCH(PosDepPos, 7)
COUNT_BENCH(PosDepPos, 8)

COUNT_BENCH(UsedTo, 1)
COUNT_BENCH(UsedTo, 2)
COUNT_BENCH(UsedTo, 3)
COUNT_BENCH(UsedTo, 4)
COUNT_BENCH(UsedTo, 5)
COUNT_BENCH(UsedTo, 6)
COUNT_BENCH(UsedTo, 7)
COUNT_BENCH(UsedTo, 8)

BASELINE_F(JoinImpl, IndexJoin, GUMFixture, 0, 0)
{
  QueryConfig conf;
  conf.threadPool = nullptr;
  std::shared_ptr<Query> q = query_PosDepPos(conf);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_PosDepPos)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_PosDepPos);
  }
}

BENCHMARK_F(JoinImpl, TaskIndexJoin, GUMFixture, 0, 0)
{
  std::shared_ptr<Query> q = query_PosDepPos(taskConfigs[1]);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_PosDepPos)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_PosDepPos);
  }
}

BASELINE(CreateThreadPool, N1, 0, 0)
{
  ThreadPool t(1);
}

BENCHMARK(CreateThreadPool, N2, 0, 0)
{
  ThreadPool t(2);
}

BENCHMARK(CreateThreadPool, N3, 0, 0)
{
  ThreadPool t(3);
}

BENCHMARK(CreateThreadPool, N4, 0, 0)
{
  ThreadPool t(4);
}

BENCHMARK(CreateThreadPool, N5, 0, 0)
{
  ThreadPool t(5);
}

BENCHMARK(CreateThreadPool, N6, 0, 0)
{
  ThreadPool t(6);
}

BENCHMARK(CreateThreadPool, N7, 0, 0)
{
  ThreadPool t(7);
}

BENCHMARK(CreateThreadPool, N8, 0, 0)
{
  ThreadPool t(8);
}

<commit_msg>Remove task join from parallel benchmark.<commit_after>#include <celero/Celero.h>

#include <forward_list>

#include <annis/query.h>
#include <annis/annosearch/exactannokeysearch.h>
#include <annis/annosearch/exactannovaluesearch.h>
#include <annis/annosearch/regexannosearch.h>

#include <annis/operators/pointing.h>
#include <annis/operators/precedence.h>

#ifdef ENABLE_VALGRIND
  #include <valgrind/callgrind.h>
#else
  #define CALLGRIND_STOP_INSTRUMENTATION

  #define CALLGRIND_START_INSTRUMENTATION
#endif // ENABLE_VALGRIND

using namespace annis;

int main(int argc, char** argv) {
  try
  {
    celero::Run(argc, argv);
    return 0;
  }
  catch(std::string ex)
  {
    std::cerr << "ERROR: " << ex << std::endl;
  }
  catch(char const* ex)
  {
    std::cerr << "ERROR: " << ex << std::endl;
  }
  catch(...)
  {
    std::cerr << "Some exception was thrown!" << std::endl;
  }

  return -1;
}

static std::shared_ptr<ThreadPool> benchmarkThreadPool = std::make_shared<ThreadPool>(8);

class GUMFixture : public celero::TestFixture
{
    public:
        GUMFixture()
          : count_PosDepPos(246), count_UsedTo(1)
        {
        }

        /*
        virtual std::vector<std::pair<int64_t, uint64_t>> getExperimentValues() const override
        {
            std::vector<std::pair<int64_t, uint64_t>> problemSpace;

            for(int64_t i=1; i <= std::thread::hardware_concurrency(); i++)
            {
              problemSpace.push_back(std::make_pair(i, uint64_t(0)));
            }
            return problemSpace;
        }
        */

        /// Before each run, build a vector of random integers.
        virtual void setUp(int64_t experimentValue)
        {
          CALLGRIND_STOP_INSTRUMENTATION;
          char* testDataEnv = std::getenv("ANNIS4_TEST_DATA");
          std::string dataDir("data");
          if (testDataEnv != NULL) {
            dataDir = testDataEnv;
          }
          db.load(dataDir + "/GUM", true);

          nonParallelConfig.numOfBackgroundTasks = 0;
          nonParallelConfig.threadPool = nullptr;

//          taskConfigs.resize(9);
          threadConfigs.reserve(8);

          for(int64_t i=1; i <= 8; i++)
          {
            QueryConfig threadCfg;
            threadCfg.threadPool = benchmarkThreadPool;
            threadCfg.numOfBackgroundTasks = i;

            threadConfigs.push_back(threadCfg);
          }
        }

        std::shared_ptr<Query> query_PosDepPos(QueryConfig config)
        {
          std::shared_ptr<Query> result = std::make_shared<Query>(db, config);

          result->addNode(std::make_shared<ExactAnnoKeySearch>(db, "pos"));
          result->addNode(std::make_shared<ExactAnnoKeySearch>(db, "pos"));

          Annotation edgeAnno = {db.strings.add("func"), 0, db.strings.add("dep")};
          result->addOperator(std::make_shared<Pointing>(db.edges, db.strings, "", "dep", edgeAnno), 0, 1);

          return result;
        }

        std::shared_ptr<Query> query_UsedTo(QueryConfig config)
        {
          std::shared_ptr<Query> result = std::make_shared<Query>(db, config);

          result->addNode(std::make_shared<RegexAnnoSearch>(db, "pos", "NN.*"));
          result->addNode(std::make_shared<ExactAnnoValueSearch>(db, "annis4_internal", "tok", "used"));
          result->addNode(std::make_shared<ExactAnnoValueSearch>(db, "annis4_internal", "tok", "to"));

          result->addOperator(std::make_shared<Precedence>(db, db.edges), 0, 1);
          result->addOperator(std::make_shared<Precedence>(db, db.edges), 1, 2);
          return result;
        }

        DB db;
        QueryConfig nonParallelConfig;
        std::vector<QueryConfig> threadConfigs;

        const int count_PosDepPos;
        const int count_UsedTo;

};

BASELINE_F(PosDepPos, NonParallel, GUMFixture, 0, 0)
{
  CALLGRIND_START_INSTRUMENTATION;
  std::shared_ptr<Query> q = query_PosDepPos(nonParallelConfig);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_PosDepPos)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_PosDepPos);
  }
  CALLGRIND_STOP_INSTRUMENTATION;
}

BASELINE_F(UsedTo, NonParallel, GUMFixture, 0, 0)
{
  CALLGRIND_START_INSTRUMENTATION;
  std::shared_ptr<Query> q = query_UsedTo(nonParallelConfig);

  int counter=0;
  while(q->next()) {
    counter++;
  }
  if(counter != count_UsedTo)
  {
    throw "Invalid count for N0, was " + std::to_string(counter) + " but should have been  " + std::to_string(count_UsedTo);
  }
  CALLGRIND_STOP_INSTRUMENTATION;
}

#define COUNT_BENCH(group, idx) \
  BENCHMARK_F(group, Thread_##idx, GUMFixture, 0, 0) \
  { \
  CALLGRIND_START_INSTRUMENTATION;\
    std::shared_ptr<Query> q = query_##group(threadConfigs[idx-1]);\
    int counter=0; \
    while(q->next()) { \
      counter++; \
    } \
    if(counter != count_##group)\
    {\
      throw "Invalid count for Thread_" #idx ", was " + std::to_string(counter) + " but should have been  " + std::to_string(count_##group);\
    }\
  CALLGRIND_STOP_INSTRUMENTATION;\
  }

COUNT_BENCH(PosDepPos, 1)
COUNT_BENCH(PosDepPos, 2)
COUNT_BENCH(PosDepPos, 3)
COUNT_BENCH(PosDepPos, 4)
COUNT_BENCH(PosDepPos, 5)
COUNT_BENCH(PosDepPos, 6)
COUNT_BENCH(PosDepPos, 7)
COUNT_BENCH(PosDepPos, 8)

COUNT_BENCH(UsedTo, 1)
COUNT_BENCH(UsedTo, 2)
COUNT_BENCH(UsedTo, 3)
COUNT_BENCH(UsedTo, 4)
COUNT_BENCH(UsedTo, 5)
COUNT_BENCH(UsedTo, 6)
COUNT_BENCH(UsedTo, 7)
COUNT_BENCH(UsedTo, 8)

BASELINE(CreateThreadPool, N1, 0, 0)
{
  ThreadPool t(1);
}

BENCHMARK(CreateThreadPool, N2, 0, 0)
{
  ThreadPool t(2);
}

BENCHMARK(CreateThreadPool, N3, 0, 0)
{
  ThreadPool t(3);
}

BENCHMARK(CreateThreadPool, N4, 0, 0)
{
  ThreadPool t(4);
}

BENCHMARK(CreateThreadPool, N5, 0, 0)
{
  ThreadPool t(5);
}

BENCHMARK(CreateThreadPool, N6, 0, 0)
{
  ThreadPool t(6);
}

BENCHMARK(CreateThreadPool, N7, 0, 0)
{
  ThreadPool t(7);
}

BENCHMARK(CreateThreadPool, N8, 0, 0)
{
  ThreadPool t(8);
}

BASELINE(MatchQueue, Vector, 0, 0)
{
  std::list<std::vector<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::vector<Match> m(2);
    queue.emplace_back(m);
  }

  std::vector<Match> m;
  while(!queue.empty())
  {
    m = queue.front();
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, VectorMove, 0, 0)
{
  std::list<std::vector<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::vector<Match> m(2);
    queue.emplace_back(m);
  }

  std::vector<Match> m;
  while(!queue.empty())
  {
    m = std::move(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, VectorMoveDeque, 0, 0)
{
  std::deque<std::vector<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::vector<Match> m(2);
    queue.emplace_back(m);
  }

  std::vector<Match> m;
  while(!queue.empty())
  {
    m = std::move(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, VectorSwap, 0, 0)
{
  std::list<std::vector<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::vector<Match> m(2);
    queue.emplace_back(m);
  }

  std::vector<Match> m;
  while(!queue.empty())
  {
    m.swap(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, VectorSwapDeque, 0, 0)
{
  std::deque<std::vector<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::vector<Match> m(2);
    queue.emplace_back(m);
  }

  std::vector<Match> m;
  while(!queue.empty())
  {
    m.swap(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, Deque, 0, 0)
{
  std::list<std::deque<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::deque<Match> m(2);
    queue.emplace_back(m);
  }

  std::deque<Match> m;
  while(!queue.empty())
  {
    m = std::move(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, DequeSwap, 0, 0)
{
  std::list<std::deque<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::deque<Match> m(2);
    queue.emplace_back(m);
  }

  std::deque<Match> m;
  while(!queue.empty())
  {
    m.swap(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, DequeSwapDeque, 0, 0)
{
  std::deque<std::deque<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::deque<Match> m(2);
    queue.emplace_back(m);
  }

  std::deque<Match> m;
  while(!queue.empty())
  {
    m.swap(queue.front());
    queue.pop_front();
  }
}

BENCHMARK(MatchQueue, List, 0, 0)
{
  std::list<std::list<Match>> queue;
  for(int i=0; i < 1000; i++)
  {
    std::list<Match> m(2);
    queue.emplace_back(m);
  }

  std::list<Match> m;
  while(!queue.empty())
  {
    m = std::move(queue.front());
    queue.pop_front();
  }
}

<|endoftext|>