我知道编辑这个网站吗?

HPC 工作流程管理器

Please Note: This version of the documentation is outdated. We recommend reading the short guide instead. It contains current information on new features.

一般信息

###什么是HPC工作流程管理器

HPC Workflow Manager 是一个 Fiji 插件,它使用户能够享受化宏脚本、定义任务、报告任务进度、将数据上传到远程组件、监控计算进度以及通过本地 Fiji 安装检查和下载结果。

HPC Workflow Manager 是在捷克共和国俄斯特拉发 IT4Innovations 开发的。

###为什么使用HPC工作流程管理器

现在,一点处理解决了我们一些最大的问题,就像旧西部的广东者使用玩具牛解决他们最大的问题一样。如果他们用一头牛来移动一棵树,而这头牛不够大或不够强大,他们当然不会尝试养一头更大的牛——他们会用两只牛。如果我们的计算机不够快或不够强大,再尝试开发更快、更强大的计算机,为什么不简单地使用多台计算机呢?

-《计算机组织与体系结构精要》,第五版,作者:空

由于摩尔指令的限制,串行执行性能的主要提升已经结束,这意味着仅仅通过获得更新的处理器并希望现有的串行程序性能,更好地可能解决大数据集和/或计算要求的问题。相反,必须使用更多的附加。多年来,个人电脑一直在朝着这个方向发展,通过多个内核、通过使用GPU加速性能、使内存更接近CPU等。尽管如此,大量数据集需要的性能。这样的性能目前只能在超级计算机中找到。

生命科学家是真正可以从如此高的性能中受益的一类用户。

HPC Workflow Manager 旨在降低个人用户获取访问的权限,并通过插件方式提供集成到斐济的方式,通过其图形用户界面方法方便用户为现有宏脚本添加大量化支持。

工作流程类型

HPC Workflow Manager客户端支持两种工作流类型:

  • SPIM;和
  • 宏观。

本指南仅说明如何使用新添加的宏工作流程类型。

如果您对 SPIM 工作流程类型感兴趣,请访问 this 页面。

如何使用

如何启动插件

从斐济菜单栏选择HelpUpdate…Manage update sites并填写将出现的登录对话框。例如,请参见图 1 中的填充对话框。

/media/plugins/hpc-workflow-manager-login.png

Figure 1: Example of a filled in login dialog.

如何登录

您需要输入帐户的用户名、密码和电子邮件。如果这是您第一次使用该插件的安装,您必须在任何位置创建一个新目录设置工作目录。如果您过去使用过 HPC Workflow Manager,则可以使用现有的工作目录。通过浏览单击按钮或输入路径来选择工作目录。该目录必须已经存在。

单击“确定”,该对话框将消失,并应出现一个流程图对话框。如果没有,那么一条新消息应该通知您填写对话框期间发生的错误。更正错误并重试。

如何创建新作品

创建与 HPC 集群的连接并从集群下载作业后,您应该会看到如图 2 所示的窗口。如果这是您第一次运行此插件,则该表将会空。

/media/plugins/hpc-workflow-manager-main-empty.png

Figure 2: Example of the main window of the HPC Workflow Manager, it displays all jobs ever submitted by the user, in this case, it is empty as it is the first time the plugin is used.

右键单击空表或表的空行以显示上下文菜单,上下文菜单的示例如图3所示。

/media/plugins/hpc-workflow-manager-context-menu.png

Figure 3: Context menu press right click on an empty row or empty table to display.

选择第一个选项“创建新作业”。将出现“创建作业”窗口。从“工作流程类型”部分中,选择“宏执行”选项。

在输入数据位置,您必须提供包含宏脚本的目录(该脚本必须命名为“user.ijm”)。如果这是您第一次使用支持宏的 HPC 工作流插件,则可以使用第 here 中的示例。 在节点配置中,通过按压力器中的向上箭头四次来选择四个节点(4)。

在“输出数据位置”部分中,保留默认选项“作业子目录”在选中状态。

现在,填写表单应如图 4 所示。如果您使用的是 Linux,则将“HelloWorld”示例脚本保存在您的主目录 (“~/HelloWorld/user.ijm”) 中,并使用该路径而不是“C:/Documents/HelloWorld”。当您确定表格填写正确后,请按“”创建按钮。

/media/plugins/hpc-workflow-manager-create-job.png

Figure 4: Example of a new Macro job configuration.

如何上传数据和宏脚本

如果您创建了一个新作业,主窗口应大致如图 5 所示。

/media/plugins/hpc-workflow-manager-created-job.png

Figure 5: A new Macro job has been created.

在开始作业之前,您需要上传脚本(“user.ijm”)。因此,您必须从上面菜单中选择“上传数据”项。如果您的脚本也需要数据,它们也应该位于用户脚本所在的相同目录中。数据将与宏脚本文件一起上传。

下载完成将出现一个计时器。当上传数据和用户脚本时,与作业相对应的单元格应指示其已“完成”(图6)。

/media/plugins/hpc-workflow-manager-upload-job.png

Figure 6: Uploading files (in this case just the user’s script) is done.

现在脚本文件已上传,可以开始作业了。

如何开始工作

让我们仔细检查一下图 6。在图中您可以看到以下内容:

  • “工作ID”-工作的识别号;
  • “状态” – 作业的当前状态可以是:
    • “Unknown” – the state of the job is not known;
    • “Configuring” – the job is being configured;
    • “Queued” – the job is in a queue and when there are available nodes it will be executed;
    • “Running” – the job was executed and it is currently running;
    • “Finished” – the job has stopped running successfully, completing its tasks;
    • “Failed” – the job has stopped running unsuccessfully, it did not complete its tasks;
    • “Canceled” – the job was stopped by the user; and
    • Disposed – the job was disposed.
  • “创建时间”——创建作业的时间。
  • “开始时间”——作业上次开始的时间。
  • “结束时间” – 作业上次结束的时间。
  • “上传”——作业是否已上传。
  • “下载”——作业是否已下载。
  • “工作流程类型”-无论是SPIM还是宏工作流程类型。

右键单击新作业以显示上下文菜单(如图3所示)。您会注意到有新的新增项目。

右键单击作业所在行,然后从上下文菜单中选择“启动作业”。

为了使用户的源代码更清晰、更容易理解,在上传时将允许用户使用各种特殊函数附加到用户脚本中,并创建一个名为“parallelMacroWrappedScript.ijm”的新文件,该文件将在集群上执行。

要检查提交的文件(例如用于调试),您可以右键单击作业并选择“在编辑器中打开宏”,您可以在其中看到用户脚本的内容以及提供大量性的附加函数定义。

最后,要启动作业,请右键单击作业并从上下文菜单中选择“启动作业”项。

###检查细节

有两种方法可以检查作业的详细信息。

第一个是查看工作的“状态”。这样就可以查看HPC集群上是否正在运行作业。在图7的情况下,作业一个“队列”状态。

/media/plugins/hpc-workflow-manager-queued-job.png

Figure 7: Job is queued.

然而,这是一种非常粗粒度的查看作业进度的方法,当它开始运行时,它不会提供任何有用的信息,直到它结束(“完成”、“失败”等)。

第二个方法是通过选择作业行或右键单击并“作业仪表板”上下文菜单项来打开所需作业的“作业仪表板”。请注意,作业必须处于“正在运行”状态才能使用此功能,您可以提前打开该窗口,当状态自动更改时才会开始显示进度。

选择“宏详细信息”选项卡并暂时忽略其余选项卡(有关其余选项卡的说明,请参见“作业仪表板”部分)。

要查看文档,请单击“宏文档”(如果尚未选择)(默认情况下应选择它)。加载进度时请等待等待。窗口右下角有一个状态栏,您可以在其中监视从 HPC 集群获取进度的过程(该文档存储在运行 HPC 集群的每个计算节点的单独进度文件中)。

您可以在图 8 中查看正在运行的作业的任务概要快照。

每行代表一个不同的任务,每列代表执行任务的不同计算节点,但提供任务描述的第一列及时。没有进度更新的单元格表示根本不会执行任务或尚未开始执行任务的节点。在第二个情况下,当进度更新到百分之零 (0%) 或更多时,将出现进度进度。

/media/plugins/hpc-workflow-manager-progress-running.png

Figure 8: The job is running and the progress indicators display the progress for each task on each compute-node.

工作仪表板

在“作业仪表板”中有以下五个选项卡:

  • “详细资料” – 此选项卡在上一份详细资料检查中进行了描述(单击here);
  • “错误输出” - 从 HPC 集群实时重定向的错误输出和警告(单击here);
  • “其他输出”- 选项卡中集群的实时重定向标准输出(点击here);
  • “作业目录” – 包含作业目录列表(输入、输出和工作)(单击here);和
  • “数据上传” – 包含已上传文件的列表(点击here);

如何下载结果

作业完成后,您可以右键单击并选择“下载结果”项目,该项目现已可用。

当“下载”窗口打开的计时器结束状态且为“完成”时,文件将被传输。您可以通过右键单击作业并选择“作业子目录”项来查看下载的文件。

如何编写宏

###先决条件

如果您不熟悉宏编程,建议先阅读Introduction into Macro Programming。这将为您提供斐济宏编程基础知识的充分介绍。 如果您选择使用脚本编辑器,您可能会发现Using the Script Editor很有用。建议使用脚本编辑器,因为它支持自动完成 HPC Workflow Manager 的附加功能。

您还应该熟悉 HPC 工作流程客户端的图形用户界面。

如何使用家具化功能(简单)

编写小型脚本为您提供相关的要素化功能,以帮助您开始在宏脚本上使用要素。

简单的问候语示例

让我们编写一个简单的“问候”宏脚本,其中每个节点都会用打印消息向其余节点打招呼,并等待其余节点也向它打招呼。然后宣布出发和结束。在所有节点都介绍之前,任何节点都不能完成。让我们开始吧:

首先,我们可以写一个串行版本:

    print("The greeting program.");
    print("Hello I am a single node.");
    print("Bye, from the only node.");

现在,让我们通过在程序中添加对 parInit() 的调用来工具化它,以启动程序的工具执行。我们还必须在程序中添加对 parFinalize() 的调用来停止工具化。现在代码应该如下所示:

parInit();
  print("The greeting program.");
  print("Hello I am a single node.");
  print("Bye, from the only node.");
parFinalize();

很好,我们的程序现在已经完成了。但是,这些消息已经没有意义了。

我们应该获取节点的id并打印它以及节点的总数(只是为了好玩)。

要获取节点的id(即其等级),我们必须调用parGetRank()

parInit();
  myRank = parGetRank();
  if (myRank == 0){
    print("The greeting program.");
  }
  print("Hello I am node number: "+myRank);
  print("Bye, from node number: "+myRank);
parFinalize();

请注意,我们填写第一个 print() 语句在if语句中,将排名与第一个 (0) 进行比较,这样做是为了只打印此消息一次。

您可以选择任何可用节点的等级,这是目前,但不一定使用第一个。您将来可能会使用不同数量的节点运行该脚本,并且保证存在的唯一等级等级(0),这是因为俱乐部有至少一个节点执行该脚本,并且分配给它的等级等级(0)。因此,if语句中的等级等级的代码将始终被执行并且仅由一个节点执行。

为了满足所有节点,我们还可以通过调用 get size parGetSize()添加用于运行脚本的节点总数(大小)。获取排名后添加以下行以获取大小:

  size = parGetSize();

威尔第一个打印修改为:

  print("Hello to all "+size+" nodes. I am node number: "+myRank);

不幸的是,这是不正确的。

如果运行足够多次,你会注意到有时候一个节点会在所有节点发出警告之前“离开”。这是因为节点节点可能会更慢地执行其代码,无法保证每一行都会同时执行,或者节点之间哪一行将首先执行。

例如,如果有两个(2)个节点,“其他输出”选项卡中的重定向输出可能如下所示:

The greeting program.
Hello I am node number: 1
Bye, form node number: 1
Hello I am node number: 0
Bye, from node number: 0

为了修正这个问题,我们提出了代码的执行流程障碍设置。

任何调用该函数的节点都会停止,直到每个节点也调用了该函数。

为此,请在警告语下方和节点出发公告上方添加parBarrier()

  print("Hello I am node number: "+myRank);
  parBarrier();
  print("Bye, from node number: "+myRank);

该脚本现在将正确运行,例如对于三 (3) 个节点,可能会打印以下输出:

Hello I am node number: 1
Hello I am node number: 3
Hello I am node number: 0
Bye, form node number: 3
Bye, from node number: 0
Bye, from node number: 1

这是正确的。现在让我们想象一号节点 (1) 和只有一号节点 (1) 带来了一块蛋糕。并希望通过打印来共享该信息。您可以使用 if 语句并比较排名,仅在特定节点中执行代码,如下所示:

 if(myRank == 1){
   print("I brought the cake.");
 }

在调用 parBarrier() 之前,将上述代码片段添加到代码区域中的任意位置(即 parInit()parFinalize() 之间)。

太好了,既然节点一个带来了蛋糕,它就想与其他节点分享。让我们想象一下蛋糕是一个由数字组成的数组。像下面这样:

  cake = newArray(1, 2, 3, 4);

有四块蛋糕。将以上行添加到if语句的主体内。在if声明上方添加以下内容:

  cake = newArray(0);

这意味着剩下的节点没有蛋糕。稍后你就会明白为什么这是必需的。

一号节点想要将它们平分。这就是为什么必须使用parScatterEqually()

parScatterEqually()将同时发送和接收一个胎儿蛋糕(合并项目)。它三个参数,要分割和发送(分散)的阵列、发送阵列的长度以及哪个节点要吐出阵列并发送它。因此,在这种情况下,您必须在if之后添加语句主体以下行:

  receivedPieces = parScatterEqually(cake, 4, 1); // Do NOT use lengthOf(cake);

请记住,其余节点没有蛋糕,无法知道大小!包括一 (1) 个节点所属的所有节点都将接收部分蛋糕。由于蛋糕的数量超过三块,因此第一个节点(rank == 0)将获得额外的块。(parScatterEqually()将始终将任何额外的节点提供给第一个节点,为避免这种情况,必须使用parScatter()并准确指定每个节点要接收多少个其元素)。

现在您可以打印节点收到的一个或多个片段。这是本节示例的最后一步。总的来说,代码现在应该如下所示:

parInit();
  myRank = parGetRank();
  if(myRank == 0){
    print("The greeting program.");
  }
  size = parGetSize();
  print("Hello to all "+size+" nodes. I am node number: "+myRank);
  cake = newArray(0);
  if(myRank == 1){
    print("I brought the cake.");
    cake = newArray(1, 2, 3, 4);
  }
  receivedPieces = parScatterEqually(cake, 4, 1);
  parBarrier();
  for(i = 0; i < lengthOf(receivedPieces); i++){
    print("I node number "+myRank+" received piece: "+receivedPieces[i]);
  }
  print("Bye, from node number: "+myRank);
parFinalize();

最后,要记住的重要一点是节点不共享内存。每个节点都是独立的,它们只能通过消息(发送数据)进行通信。目前只能通过调用parScatterEqually()parScatter()

如何使用详细报告功能(简单)

第一步是使用 parAddTasks() 函数添加所有任务。只需在 parInit() 之后调用此方法,次数与您想要的任务相同,包括每个任务的唯一描述。必须是唯一的。任务会按照添加顺序自动分配一个自动递增的 ID。

您可以将添加的任务ID存储在变量中,以便稍后处理。

第二步是调用 parReportTasks() 函数,该函数将向每个节点的详细日志输出任务 ID 列表以及任务描述。

请注意,节点之间的任务ID可能不同,因为如果用户需要,任务可能只添加到一个节点中。

第三步是调用parReportProgress()函数,将当前进度添加到进度报告文件中。

请注意,图纸只能是 0 到 100 之间的百分比,并且不能刚性移动。

其他信息可以通过调用parReportText()功能报告。

扩展问候语示例

扩展前面的要点大家互相问候并分享蛋糕的例子,我们现在添加必要的函数调用来报告每个任务的细节。

该示例可以分为四 (4) 个任务:

1.一个节点向所有其他节点介绍自己。(获取排名和大小并打印它们。)

  1. 一号节点 (1) 获得蛋糕。(用数据创建备份。)
  2. 每个节点都会收到一些蛋糕。 (节点接收到的元素,节点一这些节点分配到包括其自身剩余的所有节点。)
  3. 每个节点公布自己获得的碎片。(打印接收到的内存中的元素。)

看一下本节消耗的代码,这里将详细解释。

请注意,任务三 (3) 语句在 if 语句中。这是因为我们只需要一个节点来创建蛋糕(数据)。

在实际问题中,数据可能是一个仅在一台计算机上可用的巨大数据集,我们希望将其部分数据分散到其他节点,这些节点将利用其部分数据执行一些计算。

请注意,由于该任务仅添加到节点一(1)上,因此该任务之后的任务索引在剩余节点中将节点1。

例如,对于本节前面介绍的列表中的相同任务,以下两个节点将具有不同的任务编号:

  • 节点零 (0) 将具有:list(1) -> id(0)、list(3) -> id(1)、list(4) -> id(2)。
  • 而节点 (1) 将具有:list(1) -> id(0)、list(2) -> id(1)、list(3) -> id(2)、list(4) -> id(3)。

这可能会造成很大的困难,这就是为什么建议首先添加任务时返回的任务 ID 存储在变量中并使用它。

parInit();
  introductionTask = parAddTask("Introduction to other nodes.");

  myRank = parGetRank();
  size = parGetSize();

  if(myRank == 1){
    print("The greeting program. Now with progress reporting!");
    cakeTask = parAddTask("Get the cake.");
  }
  getPieceTask = parAddTask("Get the cake pieces.");
  annoucementTask = parAddTask("Announce the pieces you got.");
  parReportTasks();

  parReportProgress(introductionTask,0);
  print("Hello to all "+size+" nodes. I am node number: "+myRank);
  parReportProgress(introductionTask, 100);

  cake = newArray(0);
  if(myRank == 1){
    parReportProgress(cakeTask, 0);
    print("I brought the cake.");
    cake = newArray(30);
      for(i = 0; i < lengthOf(cake); i++){
        cake[i] = i;
        parReportProgress(cakeTask, i/30 * 100);
      }
      parReportProgress(cakeTask, 100);
  }

  parReportProgress(getPieceTask, 0);
  receivedPieces = parScatterEqually(cake, 10, 1);
  parReportProgress(getPieceTask, 100);

  parBarrier();

  parReportProgress(annoucementTask, 0);
  for(i = 0; i < lengthOf(receivedPieces); i++){
    print("I node number "+myRank+" received piece: "+receivedPieces[i]);
    parReportProgress(annoucementTask, i/lengthOf(receivedPieces)*100);
  }
  parReportProgress(annoucementTask, 100);

  print("Bye, from node number: "+myRank);
parFinalize();
/media/plugins/hpc-workflow-manager-progress-no-task.png

Figure 9: The job has finished and all the progress indicators are present. Note that the task “Get the cake” has a progress indicator only on node one (1) as expected. This is because this task was added in an if statement checking that the rank is one.

/media/plugins/hpc-workflow-manager-side-by-side-example.png

Figure 10: The red circle labeled zero (0) is a task performed by all nodes. It is first added, and then its progress is reported twice: once when it is zero and finally when it is done. The green circle labeled three (3) is first added and then its progress is reported as well, however, notice that all its related commands are inside the body of if statements. Notice that all calls of parAddTask() are before parReportTasks().

###可用功能(列表)

许多函数都有 MPI 对应函数,这也将列在表中以帮助熟悉 MPI 的人员。这是因为当前的实现使用 OpenMPI 4.0。但请注意,这并不意味着这将是斐济宏的 MPI 包装器,并且底层实现可能会发生变化。

函数名称 输入 输出 描述 MPI 同等
parInit 初始化玩具化,应该在玩具代码的引用。 MPI_Init  
完成 完成工件化,应该在工件代码的消耗调用它。 MPI_最终确定  
parGetRank 当前节点的Id。 返回当前节点的id。 MPI_Comm_rank
parGetSize 节点总数。 返回节点总数。 MPI_Comm_大小  
帕屏障 睡眠屏障,所有节点到达必须调用此函数的点,其中任意一个节点才能继续前进。提供同步。 MPI_Barrier  
parScatterEqual 要分割和发送的磁盘、要发送的磁盘的长度、将分割和发送磁盘的节点的等级。 一个磁盘。 这将尝试将磁盘分割为足够的部分,然后从给定的等级发送它。它接收到它应该接收的磁盘部分并返回它(包括发送这部分的排名)。如果磁盘元素的数量不能被分,就把任何外部的元素等发送到第一排(0)。
  parScatter 要分割和发送的阵列、要发送的元素数量、要接收的元素数量发送以及元素的节点的等级。 一个队列。 这与 parScatter 同样类似,但在这种情况下,用户负责提供分割阵列的参数。 MPI_Scatter
聚集 要发送的阵列、要发送的项目数、要接收的数据、接收者的项目 一个缓存。 所有等级排名将等量的阵列项发送到给定等级的单个节点。请注意,receiveCount 参数应该是分别从每个等级接收的项目数。这是 parScatter 的逆操作。 MPI_收集  
平等相聚 要发送的阵列、接收阵列中的元素数量、接收者的排名 一个阵列。 给定的排名将收到由所有排名分批发送的阵列。 这是 parScatterEqually 的逆操作。

表1:毛化函数

函数名称 输入 输出 描述    
parReportProgress 报告进度 报告进度任务 ID (ex 8)、进度百分比 (ex 85 %) 以进度形式输出节点日志中指定任务的进度。    
parReportText 报告文本 报告文本文本文字 将给定输出到节点的日志。    
par 添加任务 描述 添加任务的索引。 使用提供的描述创建一个新任务。    
parReportTasks 报告任务 报告任务无 输出所有任务 ID 及其描述。    
parEnableTiming parEnableTiming parEnableTiming 完善细节日志中每个任务的计时。它测量从 0% 细节到 100% 所消耗的时间。

表2:详细日志功能

如果您需要帮助记住这些函数及其用途,您可以使用自动完成功能来获得帮助。只需输入“par”,就会出现一个选项列表。自动完成帮助中有一个指向此页面的链接。图 10 提供了一个示例。

/media/plugins/hpc-workflow-manager-autocomplete.png

Figure 11: Function autocompletion example.

安装

HPC Workflow Manager客户端可以通过其更新站点进行安装。

说明

  • Download,安装并启动Fiji;
  • 转到PluginsMultiview ReconstructionHPC Workflow Manager
  • 勾选“P2E-IT4创新”;
  • 关闭窗户;
  • 点击“应用更改”;和
  • 重启斐济。