* Note, this program reads stored.conf, and will only
* talk to devices that are configured.
*
- * Version $Id$
- *
*/
#include "bacula.h"
static uint64_t vol_size;
static uint64_t VolBytes;
static time_t now;
-static double kbs;
static int32_t file_index;
static int end_of_tape = 0;
static uint32_t LastBlock = 0;
bindtextdomain("bacula", LOCALEDIR);
textdomain("bacula");
init_stack_dump();
+ lmgr_init_thread();
/* Sanity checks */
if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) {
static void print_total_speed()
{
- char ec1[50];
- kbs = (double)total_size / (1000 * total_time);
- Pmsg2(000, _("TotalVolumeCapacity=%sB. Total Write rate = %.1f KB/s\n"),
- edit_uint64_with_suffix(total_size, ec1), kbs);
+ char ec1[50], ec2[50];
+ uint64_t rate = total_size / total_time;
+ Pmsg2(000, _("Total Volume bytes=%sB. Total Write rate = %sB/s\n"),
+ edit_uint64_with_suffix(total_size, ec1),
+ edit_uint64_with_suffix(rate, ec2));
}
static void init_speed()
static void print_speed(uint64_t bytes)
{
- char ec1[50];
+ char ec1[50], ec2[50];
+ uint64_t rate;
+
now = time(NULL);
now -= jcr->run_time;
if (now <= 0) {
total_time += now;
total_size += bytes;
- kbs = (double)bytes / (1000 * now);
- Pmsg2(000, _("VolumeCapacity=%sB. Write rate = %.1f KB/s\n"),
- edit_uint64_with_suffix(bytes, ec1), kbs);
+ rate = bytes / now;
+ Pmsg2(000, _("Volume bytes=%sB. Write rate = %sB/s\n"),
+ edit_uint64_with_suffix(bytes, ec1),
+ edit_uint64_with_suffix(rate, ec2));
}
+/*
+ * Helper that fill a buffer with random data or not
+ */
typedef enum {
FILL_RANDOM,
FILL_ZERO
}
}
+static void mix_buffer(fill_mode_t mode, char *data, uint32_t len)
+{
+ uint32_t i;
+ uint32_t *lp = (uint32_t *)data;
+
+ if (mode == FILL_ZERO) {
+ return;
+ }
+
+ lp[0] += lp[13];
+ for (i=1; i < (len-sizeof(uint32_t))/sizeof(uint32_t)-1; i+=100) {
+ lp[i] += lp[0];
+ }
+}
+
static bool open_the_device()
{
DEV_BLOCK *block;
DEV_BLOCK *block = dcr->block;
int stat;
uint32_t block_num = 0;
- uint32_t *p;
int my_errno;
- uint32_t i;
char ed1[200];
nb_gb *= 1024*1024*1024; /* convert size from nb to GB */
init_total_speed();
fill_buffer(mode, block->buf, block->buf_len);
- p = (uint32_t *)block->buf;
Pmsg3(0, _("Begin writing %i files of %sB with raw blocks of %u bytes.\n"),
nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len);
printf("+");
fflush(stdout);
}
- if (mode == FILL_RANDOM) {
- p[0] += p[13];
- for (i=1;
- i<(block->buf_len-sizeof(uint32_t))/sizeof(uint32_t)-1;
- i+=100)
- {
- p[i] += p[0];
- }
- }
+
+ mix_buffer(mode, block->buf, block->buf_len);
+
jcr->JobBytes += stat;
} else {
}
+static bool speed_test_bacula(fill_mode_t mode, uint64_t nb_gb, uint32_t nb)
+{
+ DEV_BLOCK *block = dcr->block;
+ char ed1[200];
+ DEV_RECORD *rec;
+ uint64_t last_bytes = dev->VolCatInfo.VolCatBytes;
+ uint64_t written=0;
+
+ nb_gb *= 1024*1024*1024; /* convert size from nb to GB */
+
+ init_total_speed();
+
+ empty_block(block);
+ rec = new_record();
+ rec->data = check_pool_memory_size(rec->data, block->buf_len);
+ rec->data_len = block->buf_len-100;
+
+ fill_buffer(mode, rec->data, rec->data_len);
+
+ Pmsg3(0, _("Begin writing %i files of %sB with blocks of %u bytes.\n"),
+ nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len);
+
+ for (uint32_t j=0; j<nb; j++) {
+ written = 0;
+ init_speed();
+ for ( ; written < nb_gb; ) {
+
+ if (!write_record_to_block(block, rec)) {
+ Pmsg0(0, _("\nError writing record to block.\n"));
+ goto bail_out;
+ }
+ if (!write_block_to_dev(dcr)) {
+ Pmsg0(0, _("\nError writing block to device.\n"));
+ goto bail_out;
+ }
+
+ if ((block->BlockNumber % 500) == 0) {
+ printf("+");
+ fflush(stdout);
+ }
+ written += dev->VolCatInfo.VolCatBytes - last_bytes;
+ last_bytes = dev->VolCatInfo.VolCatBytes;
+ mix_buffer(mode, rec->data, rec->data_len);
+ }
+ printf("\n");
+ weofcmd();
+ print_speed(written);
+ }
+ print_total_speed();
+ printf("\n");
+ free_record(rec);
+ return true;
+
+bail_out:
+ free_record(rec);
+ return false;
+}
+
+/* TODO: use UAContext */
+static int btape_find_arg(const char *keyword)
+{
+ for (int i=1; i<argc; i++) {
+ if (strcasecmp(keyword, argk[i]) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
#define ok(a) if (!(a)) return
/*
*/
static void speed_test()
{
- dev->rewind(dcr);
- Pmsg0(0, _("Test with zero data, should give the maximum throughput.\n"));
- ok(speed_test_raw(FILL_ZERO, 1, 3));
- ok(speed_test_raw(FILL_ZERO, 2, 3));
- ok(speed_test_raw(FILL_ZERO, 4, 3));
-
- Pmsg0(0, _("Test with random data, should give the minimum throughput.\n"));
- ok(speed_test_raw(FILL_RANDOM, 1, 3));
- ok(speed_test_raw(FILL_RANDOM, 2, 3));
- ok(speed_test_raw(FILL_RANDOM, 4, 3));
+ bool do_zero=true, do_random=true, do_block=true, do_raw=true;
+ uint32_t file_size=0, nb_file=3;
+ int32_t i;
+
+ i = btape_find_arg("file_size");
+ if (i > 0) {
+ file_size = atoi(argv[i]);
+ if (file_size > 100) {
+ Pmsg0(0, _("The file_size is too big, stop this test with Ctrl-c.\n"));
+ }
+ }
+
+ i = btape_find_arg("nb_file");
+ if (i > 0) {
+ nb_file = atoi(argv[i]);
+ }
+
+ if (btape_find_arg("skip_zero") > 0) {
+ do_zero = false;
+ }
+
+ if (btape_find_arg("skip_random") > 0) {
+ do_random = false;
+ }
+
+ if (btape_find_arg("skip_raw") > 0) {
+ do_raw = false;
+ }
+
+ if (btape_find_arg("skip_block") > 0) {
+ do_block = false;
+ }
+
+ if (do_raw) {
+ dev->rewind(dcr);
+ if (do_zero) {
+ Pmsg0(0, _("Test with zero data, should give the "
+ "maximum throughput.\n"));
+ if (file_size) {
+ ok(speed_test_raw(FILL_ZERO, file_size, nb_file));
+ } else {
+ ok(speed_test_raw(FILL_ZERO, 1, nb_file));
+ ok(speed_test_raw(FILL_ZERO, 2, nb_file));
+ ok(speed_test_raw(FILL_ZERO, 4, nb_file));
+ }
+ }
+
+ if (do_random) {
+ Pmsg0(0, _("Test with random data, should give the minimum "
+ "throughput.\n"));
+ if (file_size) {
+ ok(speed_test_raw(FILL_RANDOM, file_size, nb_file));
+ } else {
+ ok(speed_test_raw(FILL_RANDOM, 1, nb_file));
+ ok(speed_test_raw(FILL_RANDOM, 2, nb_file));
+ ok(speed_test_raw(FILL_RANDOM, 4, nb_file));
+ }
+ }
+ }
+
+ if (do_block) {
+ dev->rewind(dcr);
+ if (do_zero) {
+ Pmsg0(0, _("Test with zero data and bacula block structure.\n"));
+ if (file_size) {
+ ok(speed_test_bacula(FILL_ZERO, file_size, nb_file));
+ } else {
+ ok(speed_test_bacula(FILL_ZERO, 1, nb_file));
+ ok(speed_test_bacula(FILL_ZERO, 2, nb_file));
+ ok(speed_test_bacula(FILL_ZERO, 4, nb_file));
+ }
+ }
+
+ if (do_random) {
+ Pmsg0(0, _("Test with random data, should give the minimum "
+ "throughput.\n"));
+ if (file_size) {
+ ok(speed_test_bacula(FILL_RANDOM, file_size, nb_file));
+ } else {
+ ok(speed_test_bacula(FILL_RANDOM, 1, nb_file));
+ ok(speed_test_bacula(FILL_RANDOM, 2, nb_file));
+ ok(speed_test_bacula(FILL_RANDOM, 4, nb_file));
+ }
+ }
+ }
}
const int num_recs = 10000;
{
DEV_RECORD rec;
DEV_BLOCK *block = dcr->block;
- char ec1[50];
+ char ec1[50], ec2[50];
char buf1[100], buf2[100];
- uint32_t i;
uint64_t write_eof;
+ uint64_t rate;
uint32_t min_block_size;
int fd;
struct tm tm;
rec.Stream = STREAM_FILE_DATA;
/* Mix up the data just a bit */
- uint32_t *lp = (uint32_t *)rec.data;
- lp[0] += lp[13];
- for (i=1; i < (rec.data_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i+=100) {
- lp[i] += lp[0];
- }
+ mix_buffer(FILL_RANDOM, rec.data, rec.data_len);
Dmsg4(250, "before write_rec FI=%d SessId=%d Strm=%s len=%d\n",
rec.FileIndex, rec.VolSessionId,
if (now <= 0) {
now = 1; /* prevent divide error */
}
- kbs = (double)dev->VolCatInfo.VolCatBytes / (1000.0 * (double)now);
- Pmsg5(-1, _("Wrote block=%u, file,blk=%u,%u VolBytes=%s rate=%.1f KB/s\n"),
+ rate = dev->VolCatInfo.VolCatBytes / now;
+ Pmsg5(-1, _("Wrote block=%u, file,blk=%u,%u VolBytes=%s rate=%sB/s\n"),
block->BlockNumber, dev->file, dev->block_num,
- edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
+ edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1),
+ edit_uint64_with_suffix(rate, ec2));
}
/* Every X blocks (dev->max_file_size) write an EOF.
*/
#endif
}
- /* Get out after writing 100 blocks to the second tape */
- if (++BlockNumber > 100 && stop != 0) { /* get out */
- Pmsg0(000, _("Wrote 100 blocks on second tape. Done.\n"));
+ /* Get out after writing 1000 blocks to the second tape */
+ if (++BlockNumber > 1000 && stop != 0) { /* get out */
+ Pmsg0(000, _("Wrote 1000 blocks on second tape. Done.\n"));
break;
}
}
FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
- /* Get out after writing 100 blocks to the second tape */
- if (BlockNumber > 100 && stop != 0) { /* get out */
+ /* Get out after writing 1000 blocks to the second tape */
+ if (BlockNumber > 1000 && stop != 0) { /* get out */
char ed1[50];
Pmsg1(-1, "Done writing %s records ...\n",
edit_uint64_with_commas(write_count, ed1));
break;
}
- }
+ } /* end big for loop */
+
if (vol_num > 1) {
Dmsg0(100, "Write_end_session_label()\n");
/* Create Job status for end of session label */
Pmsg2(0, _("Could not create state file: %s ERR=%s\n"), buf,
be.bstrerror());
exit_code = 1;
+ ok = false;
}
now = time(NULL);
(void)localtime_r(&now, &tm);
strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm);
- if (simple) {
- Pmsg3(01, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"),
- buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
- } else {
- Pmsg3(0, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"),
- buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
- }
+ if (ok) {
+ if (simple) {
+ Pmsg3(0, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"),
+ buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
+ } else {
+ Pmsg3(0, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"),
+ buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
+ }
- jcr->dcr->block = block;
- if (!do_unfill()) {
- Pmsg0(000, _("do_unfill failed.\n"));
- exit_code = 1;
+ jcr->dcr->block = block;
+ if (!do_unfill()) {
+ Pmsg0(000, _("do_unfill failed.\n"));
+ exit_code = 1;
+ ok = false;
+ }
+ } else {
+ Pmsg1(000, _("%s: Error during test.\n"), buf1);
}
-
dev->min_block_size = min_block_size;
free_memory(rec.data);
}
this_block = NULL;
}
+/*
+ * This is the second part of the fill command. After the tape or
+ * tapes are written, we are called here to reread parts, particularly
+ * the last block.
+ */
static bool do_unfill()
{
DEV_BLOCK *block = dcr->block;
VolBytes = 0;
LastBlock = 0;
- Dmsg0(20, "Enter do_unfill\n");
+ Pmsg0(000, "Enter do_unfill\n");
dev->set_cap(CAP_ANONVOLS); /* allow reading any volume */
dev->clear_cap(CAP_LABEL); /* don't label anything here */
}
autochanger = autoload_device(dcr, 1, NULL);
if (autochanger != 1) {
+ Pmsg1(100, "Autochanger returned: %d\n", autochanger);
dev->close();
get_cmd(_("Mount first tape. Press enter when ready: "));
+ Pmsg0(000, "\n");
}
}
autochanger = autoload_device(dcr, 1, NULL);
if (autochanger != 1) {
+ Pmsg1(100, "Autochanger returned: %d\n", autochanger);
dev->close();
get_cmd(_("Mount second tape. Press enter when ready: "));
+ Pmsg0(000, "\n");
}
dev->clear_read();
*/
static int flush_block(DEV_BLOCK *block, int dump)
{
- char ec1[50];
+ char ec1[50], ec2[50];
+ uint64_t rate;
DEV_BLOCK *tblock;
uint32_t this_file, this_block_num;
if (now <= 0) {
now = 1; /* don't divide by zero */
}
- kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
+ rate = dev->VolCatInfo.VolCatBytes / now;
vol_size = dev->VolCatInfo.VolCatBytes;
- Pmsg4(000, _("End of tape %d:%d. VolumeCapacity=%s. Write rate = %.1f KB/s\n"),
+ Pmsg4(000, _("End of tape %d:%d. Volume Bytes=%s. Write rate = %sB/s\n"),
dev->file, dev->block_num,
- edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
+ edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1),
+ edit_uint64_with_suffix(rate, ec2));
if (simple) {
stop = -1; /* stop, but do simplified test */
uint32_t block_num = 0;
uint32_t *p;
int my_errno;
- uint32_t i;
fill_buffer(FILL_RANDOM, block->buf, block->buf_len);
init_speed();
printf("+");
fflush(stdout);
}
- p[0] += p[13];
- for (i=1; i<(block->buf_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i+=100) {
- p[i] += p[0];
- }
+
+ mix_buffer(FILL_RANDOM, block->buf, block->buf_len);
+
jcr->JobBytes += stat;
continue;
}
{NT_("rewind"), rewindcmd, _("rewind the tape")},
{NT_("scan"), scancmd, _("read() tape block by block to EOT and report")},
{NT_("scanblocks"),scan_blocks, _("Bacula read block by block to EOT and report")},
- {NT_("speed"), speed_test, _("try different configuration and report drive speed")},
+ {NT_("speed"), speed_test, _("[file_size=n(GB)|nb_file=3|skip_zero|skip_random|skip_raw|skip_block] report drive speed")},
{NT_("status"), statcmd, _("print tape status")},
{NT_("test"), testcmd, _("General test Bacula tape functions")},
{NT_("weof"), weofcmd, _("write an EOF on the tape")},
}
autochanger = autoload_device(dcr, 1, NULL);
if (autochanger != 1) {
+ Pmsg1(100, "Autochanger returned: %d\n", autochanger);
fprintf(stderr, _("Mount blank Volume on device %s and press return when ready: "),
dev->print_name());
dev->close();
getchar();
+ Pmsg0(000, "\n");
}
labelcmd();
VolumeName = NULL;
static bool my_mount_next_read_volume(DCR *dcr)
{
- char ec1[50];
+ char ec1[50], ec2[50];
+ uint64_t rate;
JCR *jcr = dcr->jcr;
DEV_BLOCK *block = dcr->block;
if (now <= 0) {
now = 1;
}
- kbs = (double)VolBytes / (1000.0 * (double)now);
- Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%.1f KB/s\n"), block->BlockNumber,
- edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
+ rate = VolBytes / now;
+ Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%sB/s\n"), block->BlockNumber,
+ edit_uint64_with_commas(VolBytes, ec1),
+ edit_uint64_with_suffix(rate, ec2));
if (strcmp(dcr->VolumeName, "TestVolume2") == 0) {
end_of_tape = 1;