/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
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, _("Total Volume bytes=%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, _("Volume bytes=%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.
*/
if (compare_blocks(last_block, block)) {
if (simple) {
Pmsg0(-1, _("\nThe last block on the tape matches. Test succeeded.\n\n"));
+ rc = true;
} else {
Pmsg0(-1, _("\nThe last block of the first tape matches.\n\n"));
}
*/
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. Volume Bytes=%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")},
bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
{
Dmsg0(20, "Enter dir_get_volume_info\n");
- bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
+ dcr->setVolCatName(dcr->VolumeName);
return 1;
}
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;
DCR *dcr = jcr->dcr;
VolumeName = VolName;
vol_num = volnum;
- bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
- bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
+ dev->setVolCatName(VolName);
+ dcr->setVolCatName(VolName);
bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
dcr->VolCatInfo.Slot = volnum;
dcr->VolCatInfo.InChanger = true;